diff --git a/src/cmap/auth/gssapi.ts b/src/cmap/auth/gssapi.ts index e4e2658db2..7ace642abe 100644 --- a/src/cmap/auth/gssapi.ts +++ b/src/cmap/auth/gssapi.ts @@ -36,7 +36,7 @@ async function externalCommand( }>); } -let krb: typeof Kerberos; +let krb: Kerberos; export class GSSAPI extends AuthProvider { override async auth(authContext: AuthContext): Promise { diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index 1a4db3401f..061d7f8332 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -695,7 +695,11 @@ export class CryptoConnection extends Connection { ): Promise { const { autoEncrypter } = this; if (!autoEncrypter) { - throw new MongoMissingDependencyError('No AutoEncrypter available for encryption'); + // TODO(NODE-6065): throw a MongoRuntimeError in Node V7 + // @ts-expect-error No cause provided because there is no underlying error. + throw new MongoMissingDependencyError('No AutoEncrypter available for encryption', { + dependencyName: 'n/a' + }); } const serverWireVersion = maxWireVersion(this); diff --git a/src/cmap/wire_protocol/compression.ts b/src/cmap/wire_protocol/compression.ts index 06c83f2912..31d2bec251 100644 --- a/src/cmap/wire_protocol/compression.ts +++ b/src/cmap/wire_protocol/compression.ts @@ -45,7 +45,7 @@ const ZSTD_COMPRESSION_LEVEL = 3; const zlibInflate = promisify(zlib.inflate.bind(zlib)); const zlibDeflate = promisify(zlib.deflate.bind(zlib)); -let zstd: typeof ZStandard; +let zstd: ZStandard; let Snappy: SnappyLib | null = null; function loadSnappy() { if (Snappy == null) { diff --git a/src/deps.ts b/src/deps.ts index 7a3c121f68..c3517ebc52 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -18,21 +18,22 @@ function makeErrorModule(error: any) { }); } -export let Kerberos: typeof import('kerberos') | { kModuleError: MongoMissingDependencyError } = - makeErrorModule( - new MongoMissingDependencyError( - 'Optional module `kerberos` not found. Please install it to enable kerberos authentication' - ) - ); +export type Kerberos = typeof import('kerberos') | { kModuleError: MongoMissingDependencyError }; -export function getKerberos(): typeof Kerberos | { kModuleError: MongoMissingDependencyError } { +export function getKerberos(): Kerberos { + let kerberos: Kerberos; try { // Ensure you always wrap an optional require in the try block NODE-3199 - Kerberos = require('kerberos'); - return Kerberos; - } catch { - return Kerberos; + kerberos = require('kerberos'); + } catch (error) { + kerberos = makeErrorModule( + new MongoMissingDependencyError( + 'Optional module `kerberos` not found. Please install it to enable kerberos authentication', + { cause: error, dependencyName: 'kerberos' } + ) + ); } + return kerberos; } export interface KerberosClient { @@ -57,20 +58,22 @@ type ZStandardLib = { decompress(buf: Buffer): Promise; }; -export let ZStandard: ZStandardLib | { kModuleError: MongoMissingDependencyError } = - makeErrorModule( - new MongoMissingDependencyError( - 'Optional module `@mongodb-js/zstd` not found. Please install it to enable zstd compression' - ) - ); +export type ZStandard = ZStandardLib | { kModuleError: MongoMissingDependencyError }; -export function getZstdLibrary(): typeof ZStandard | { kModuleError: MongoMissingDependencyError } { +export function getZstdLibrary(): ZStandardLib | { kModuleError: MongoMissingDependencyError } { + let ZStandard: ZStandardLib | { kModuleError: MongoMissingDependencyError }; try { ZStandard = require('@mongodb-js/zstd'); - return ZStandard; - } catch { - return ZStandard; + } catch (error) { + ZStandard = makeErrorModule( + new MongoMissingDependencyError( + 'Optional module `@mongodb-js/zstd` not found. Please install it to enable zstd compression', + { cause: error, dependencyName: 'zstd' } + ) + ); } + + return ZStandard; } /** @@ -100,11 +103,12 @@ export function getAwsCredentialProvider(): // Ensure you always wrap an optional require in the try block NODE-3199 const credentialProvider = require('@aws-sdk/credential-providers'); return credentialProvider; - } catch { + } catch (error) { return makeErrorModule( new MongoMissingDependencyError( 'Optional module `@aws-sdk/credential-providers` not found.' + - ' Please install it to enable getting aws credentials via the official sdk.' + ' Please install it to enable getting aws credentials via the official sdk.', + { cause: error, dependencyName: '@aws-sdk/credential-providers' } ) ); } @@ -120,11 +124,12 @@ export function getGcpMetadata(): GcpMetadata { // Ensure you always wrap an optional require in the try block NODE-3199 const credentialProvider = require('gcp-metadata'); return credentialProvider; - } catch { + } catch (error) { return makeErrorModule( new MongoMissingDependencyError( 'Optional module `gcp-metadata` not found.' + - ' Please install it to enable getting gcp credentials via the official sdk.' + ' Please install it to enable getting gcp credentials via the official sdk.', + { cause: error, dependencyName: 'gcp-metadata' } ) ); } @@ -150,10 +155,10 @@ export function getSnappy(): SnappyLib | { kModuleError: MongoMissingDependencyE // Ensure you always wrap an optional require in the try block NODE-3199 const value = require('snappy'); return value; - } catch (cause) { + } catch (error) { const kModuleError = new MongoMissingDependencyError( 'Optional module `snappy` not found. Please install it to enable snappy compression', - { cause } + { cause: error, dependencyName: 'snappy' } ); return { kModuleError }; } @@ -184,10 +189,10 @@ export function getSocks(): SocksLib | { kModuleError: MongoMissingDependencyErr // Ensure you always wrap an optional require in the try block NODE-3199 const value = require('socks'); return value; - } catch (cause) { + } catch (error) { const kModuleError = new MongoMissingDependencyError( 'Optional module `socks` not found. Please install it to connections over a SOCKS5 proxy', - { cause } + { cause: error, dependencyName: 'socks' } ); return { kModuleError }; } @@ -234,16 +239,23 @@ interface AWS4 { }; } -export let aws4: AWS4 | { kModuleError: MongoMissingDependencyError } = makeErrorModule( - new MongoMissingDependencyError( - 'Optional module `aws4` not found. Please install it to enable AWS authentication' - ) -); +export const aws4: AWS4 | { kModuleError: MongoMissingDependencyError } = loadAws4(); -try { - // Ensure you always wrap an optional require in the try block NODE-3199 - aws4 = require('aws4'); -} catch {} // eslint-disable-line +function loadAws4() { + let aws4: AWS4 | { kModuleError: MongoMissingDependencyError }; + try { + aws4 = require('aws4'); + } catch (error) { + aws4 = makeErrorModule( + new MongoMissingDependencyError( + 'Optional module `aws4` not found. Please install it to enable AWS authentication', + { cause: error, dependencyName: 'aws4' } + ) + ); + } + + return aws4; +} /** A utility function to get the instance of mongodb-client-encryption, if it exists. */ export function getMongoDBClientEncryption(): @@ -256,10 +268,10 @@ export function getMongoDBClientEncryption(): // Cannot be moved to helper utility function, bundlers search and replace the actual require call // in a way that makes this line throw at bundle time, not runtime, catching here will make bundling succeed mongodbClientEncryption = require('mongodb-client-encryption'); - } catch (cause) { + } catch (error) { const kModuleError = new MongoMissingDependencyError( 'Optional module `mongodb-client-encryption` not found. Please install it to use auto encryption or ClientEncryption.', - { cause } + { cause: error, dependencyName: 'mongodb-client-encryption' } ); return { kModuleError }; } diff --git a/src/encrypter.ts b/src/encrypter.ts index 24fe33a7b9..fbcf7c195d 100644 --- a/src/encrypter.ts +++ b/src/encrypter.ts @@ -128,7 +128,11 @@ export class Encrypter { if ('kModuleError' in mongodbClientEncryption) { throw new MongoMissingDependencyError( 'Auto-encryption requested, but the module is not installed. ' + - 'Please add `mongodb-client-encryption` as a dependency of your project' + 'Please add `mongodb-client-encryption` as a dependency of your project', + { + cause: mongodbClientEncryption['kModuleError'], + dependencyName: 'mongodb-client-encryption' + } ); } } diff --git a/src/error.ts b/src/error.ts index ffb85435e1..28c269af6b 100644 --- a/src/error.ts +++ b/src/error.ts @@ -1008,6 +1008,11 @@ export class MongoMissingCredentialsError extends MongoAPIError { * @category Error */ export class MongoMissingDependencyError extends MongoAPIError { + dependencyName: string; + + /** @remarks This property is assigned in the `Error` constructor. */ + declare cause: Error; + /** * **Do not use this constructor!** * @@ -1019,8 +1024,9 @@ export class MongoMissingDependencyError extends MongoAPIError { * * @public **/ - constructor(message: string, options: { cause?: Error } = {}) { + constructor(message: string, options: { cause: Error; dependencyName: string }) { super(message, options); + this.dependencyName = options.dependencyName; } override get name(): string {