From 0a3019856409f6fee385773dc1a2d6b287f9e8de Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Mon, 9 Nov 2020 16:07:30 -0500 Subject: [PATCH 1/6] feat: :art: Add MongoOptions interface Adds MongoOptions representing the internal view of the specified options. NODE-2698 --- package-lock.json | 66 +++++++++++------ package.json | 4 +- src/index.ts | 1 + src/mongo_client.ts | 19 ++++- src/mongo_client_options.ts | 139 ++++++++++++++++++++++++++++++++++++ 5 files changed, 205 insertions(+), 24 deletions(-) create mode 100644 src/mongo_client_options.ts diff --git a/package-lock.json b/package-lock.json index 075ffbfe9c9..4adfcc4bd3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -312,21 +312,22 @@ "dev": true }, "@microsoft/api-extractor": { - "version": "7.9.11", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.9.11.tgz", - "integrity": "sha512-t+LwGAuTjr+odFEl5xV3vl7qOWf84CM8BWKgb93kEnVd8uha3KfuWtDfnstxG4oC/TL6tu5+9rOwKJiNIidf2A==", + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.11.2.tgz", + "integrity": "sha512-iZPv22j9K02cbwIDblOgF1MxZG+KWovp3CQpWCD6UC/+YYO4DfLxX5uZYVNzfgT4vU8fN0rugJmGm85rHX6Ouw==", "dev": true, "requires": { - "@microsoft/api-extractor-model": "7.8.19", + "@microsoft/api-extractor-model": "7.10.8", "@microsoft/tsdoc": "0.12.19", - "@rushstack/node-core-library": "3.30.0", - "@rushstack/ts-command-line": "4.6.4", + "@rushstack/node-core-library": "3.34.7", + "@rushstack/rig-package": "0.2.7", + "@rushstack/ts-command-line": "4.7.6", "colors": "~1.2.1", "lodash": "~4.17.15", "resolve": "~1.17.0", "semver": "~7.3.0", "source-map": "~0.6.1", - "typescript": "~3.9.5" + "typescript": "~4.0.5" }, "dependencies": { "semver": { @@ -336,21 +337,21 @@ "dev": true }, "typescript": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", - "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", + "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", "dev": true } } }, "@microsoft/api-extractor-model": { - "version": "7.8.19", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.8.19.tgz", - "integrity": "sha512-tEEPuww0Gbyw9LuTcJ7nDCTjb+aLSAox8Xl9/iSxNTv5yHJN1QX3cqajlC3ibDHlRz7oMpQfHZX7YpAygbgIvg==", + "version": "7.10.8", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.10.8.tgz", + "integrity": "sha512-9TfiCTPnkUeLaYywZeg9rYbVPX9Tj6AAkO6ThnjSE0tTPLjMcL3RiHkqn0BJ4+aGcl56APwo32zj5+kG+NqxYA==", "dev": true, "requires": { "@microsoft/tsdoc": "0.12.19", - "@rushstack/node-core-library": "3.30.0" + "@rushstack/node-core-library": "3.34.7" } }, "@microsoft/tsdoc": { @@ -389,9 +390,9 @@ } }, "@rushstack/node-core-library": { - "version": "3.30.0", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.30.0.tgz", - "integrity": "sha512-vZo1fi/ObL3CmRXlQUX/E1xL9KL9arBfCJ7pYf3O/vFrD8ffSfpQ6+6lhgAsKrCIM5Epddsgeb2REPxMwYZX1g==", + "version": "3.34.7", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.34.7.tgz", + "integrity": "sha512-7FwJ0jmZsh7bDIZ1IqDNphY9Kc6aAi1D2K8jiq+da4flMyL84HNeq2KxvwFLzjLwu3eMr88X+oBpgxCTD5Y57Q==", "dev": true, "requires": { "@types/node": "10.17.13", @@ -419,10 +420,29 @@ } } }, + "@rushstack/rig-package": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.2.7.tgz", + "integrity": "sha512-hI1L0IIzCHqH/uW64mKqEQ0/MANA/IklVId3jGpj1kt9RJcBdeNUIlzDtHl437LZRAuEA8CyotRHzG6YDgWlTw==", + "dev": true, + "requires": { + "@types/node": "10.17.13", + "resolve": "~1.17.0", + "strip-json-comments": "~3.1.1" + }, + "dependencies": { + "@types/node": { + "version": "10.17.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz", + "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==", + "dev": true + } + } + }, "@rushstack/ts-command-line": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.6.4.tgz", - "integrity": "sha512-ubIANZimyU07+ChU56LfiD36NJ8gvw1txlvUP20GYNQi4lf5N0xEnev4r+AtKkOdnowpGy60ObGmYxSUpSacpw==", + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.7.6.tgz", + "integrity": "sha512-falJVNfpJtsL3gJaY77JXXycfzhzB9VkKhqEfjRWD69/f6ezMUorPR6Nc90MnIaWgePTcdTJPZibxOQrNpu1Uw==", "dev": true, "requires": { "@types/argparse": "1.0.38", @@ -6483,6 +6503,12 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, + "spec-xunit-file": { + "version": "0.0.1-3", + "resolved": "https://registry.npmjs.org/spec-xunit-file/-/spec-xunit-file-0.0.1-3.tgz", + "integrity": "sha1-hVpmq4w4LrMWXfkoqB0HSQKdI4Y=", + "dev": true + }, "split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", diff --git a/package.json b/package.json index 9ddf80835a7..0d26cd48850 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", - "@microsoft/api-extractor": "^7.9.10", + "@microsoft/api-extractor": "^7.11.2", "@microsoft/tsdoc-config": "^0.13.5", "@types/aws4": "^1.5.1", "@types/bl": "^2.1.0", @@ -66,8 +66,8 @@ "sinon": "^4.3.0", "sinon-chai": "^3.2.0", "snappy": "^6.3.0", - "spec-xunit-file": "0.0.1-3", "source-map-support": "^0.5.19", + "spec-xunit-file": "0.0.1-3", "standard-version": "^7.1.0", "through2": "^3.0.1", "ts-node": "^9.0.0", diff --git a/src/index.ts b/src/index.ts index ffcc9e67339..074e433783a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -296,3 +296,4 @@ export type { ClientMetadataOptions } from './utils'; export type { WriteConcern, W, WriteConcernOptions } from './write_concern'; +export type { MongoOptions } from './mongo_client_options'; diff --git a/src/mongo_client.ts b/src/mongo_client.ts index ad01cc1f041..163ddb760b2 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -18,6 +18,7 @@ import type { Topology } from './sdam/topology'; import type { ClientSession, ClientSessionOptions } from './sessions'; import type { OperationParent } from './operations/command'; import type { TagSet } from './sdam/server_description'; +import { MongoOptions, parseOptions } from './mongo_client_options'; /** @public */ export enum LogLevel { @@ -269,6 +270,16 @@ export class MongoClient extends EventEmitter implements OperationParent { s: MongoClientPrivate; topology?: Topology; + /** + * The consolidate, parsed, transformed and merged options. + * @internal + */ + options: MongoOptions; + + // debugging + originalUri; + originalOptions; + constructor(url: string, options?: MongoClientOptions) { super(); @@ -278,16 +289,20 @@ export class MongoClient extends EventEmitter implements OperationParent { // NOTE: need this to prevent deprecation notice from being inherited in Db, Collection delete options.promiseLibrary; } + this.originalUri = url; + this.originalOptions = options; + + this.options = parseOptions(url, options); // The internal state this.s = { url, - options: options || {}, + options: options ?? {}, dbCache: new Map(), sessions: new Set(), readConcern: ReadConcern.fromOptions(options), writeConcern: WriteConcern.fromOptions(options), - readPreference: ReadPreference.fromOptions(options) || ReadPreference.primary, + readPreference: ReadPreference.fromOptions(options) ?? ReadPreference.primary, bsonOptions: resolveBSONOptions(options), namespace: new MongoDBNamespace('admin'), logger: options?.logger ?? new Logger('MongoClient') diff --git a/src/mongo_client_options.ts b/src/mongo_client_options.ts new file mode 100644 index 00000000000..1775779a5d9 --- /dev/null +++ b/src/mongo_client_options.ts @@ -0,0 +1,139 @@ +import type { MongoCredentials } from './cmap/auth/mongo_credentials'; +import type { CompressorName } from './cmap/wire_protocol/compression'; +import type { AutoEncryptionOptions } from './deps'; +import type { Logger } from './logger'; +import type { DriverInfo, MongoClientOptions, PkFactory } from './mongo_client'; +import type { ReadConcern } from './read_concern'; +import type { ReadPreference } from './read_preference'; +import type { WriteConcern } from './write_concern'; + +import type { ConnectionOptions as TLSConnectionOptions } from 'tls'; +import type { TcpSocketConnectOpts as ConnectionOptions } from 'net'; +import type { BSONSerializeOptions } from './bson'; +import { MongoParseError } from './error'; +import { URL } from 'url'; + +/** + * Mongo Client Options + * @internal + */ +export interface MongoOptions + extends BSONSerializeOptions, + Omit, + Omit { + hosts: { host: string; port: number }[]; + srv: boolean; + + autoEncryption: AutoEncryptionOptions; + credentials: MongoCredentials; + compression: CompressorName; + compressors: CompressorName[]; + connectTimeoutMS: number; + dbName: string; + directConnection: boolean; + domainsEnabled: boolean; + driverInfo: DriverInfo; + forceServerObjectId: boolean; + gssapiServiceName: string; + ha: boolean; + haInterval: number; + heartbeatFrequencyMS: number; + keepAlive: boolean; + keepAliveInitialDelay: number; + localThresholdMS: number; + logger: Logger; + maxIdleTimeMS: number; + + // poolSize: number; + maxPoolSize: number; + + maxStalenessSeconds: number; + + // minSize: number; + minPoolSize: number; + + monitorCommands: boolean; + noDelay: boolean; + numberOfRetries: number; + pkFactory: PkFactory; + promiseLibrary: PromiseConstructorLike; + raw: boolean; + readConcern: ReadConcern; + readPreference: ReadPreference; + reconnectInterval: number; + reconnectTries: number; + replicaSet: string; + retryReads: boolean; + retryWrites: boolean; + serverSelectionTimeoutMS: number; + serverSelectionTryOnce: boolean; + socketTimeoutMS: number; + + /** + * If set TLS enabled, equivalent to setting the ssl option. + * + * ### Additional options: + * + * | nodejs option | MongoDB equivalent | type | + * |:---------------------|----------------------------------------------------|:---------------------------------------| + * | `ca` | sslCA, tlsCAFile | `string \| Buffer \| Buffer[]` | + * | `crl` | sslCRL | `string \| Buffer \| Buffer[]` | + * | `cert` | sslCert, tlsCertificateFile, tlsCertificateKeyFile | `string \| Buffer \| Buffer[]` | + * | `key` | sslKey, tlsCertificateKeyFile | `string \| Buffer \| KeyObject[]` | + * | `passphrase` | sslPass, tlsCertificateKeyFilePassword | `string` | + * | `rejectUnauthorized` | sslValidate | `boolean` | + * + */ + tls: boolean; + tlsAllowInvalidCertificates: boolean; + tlsAllowInvalidHostnames: boolean; + tlsInsecure: boolean; + + waitQueueMultiple: number; + waitQueueTimeoutMS: number; + writeConcern: WriteConcern; + zlibCompressionLevel: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | undefined; + /** + * Turn these options into a reusable options dictionary + */ + toJSON(): Record; + /** + * Turn these options into a reusable connection URI + */ + toURI(): string; +} + +const HOSTS_RX = new RegExp( + '(?mongodb(?:\\+srv|)):\\/\\/(?:(?[^:]*)(?::(?[^@]*))?@)?(?[^\\/?]*)(?.*)' +); + +export function parseURI(uri: string): { srv: boolean; url: URL; hosts: string[] } { + const match = uri.match(HOSTS_RX); + if (!match) { + throw new MongoParseError('Invalid connection string'); + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-expect-error + const { protocol, username, password, hosts, rest } = match.groups; + if (!protocol || !hosts) { + throw new MongoParseError('Invalid connection string, protocol and host(s) required'); + } + const authString = `${username ? `${password ? `${username}:${password}` : username}` : ''}`; + return { + srv: protocol.includes('srv'), + url: new URL(`${protocol.toLowerCase()}://${authString}@dummyHostname${rest}`), + hosts: hosts.split(',') + }; +} + +export function parseOptions( + uri: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options: MongoClientOptions = {} +): Readonly { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { srv, url, hosts } = parseURI(uri); + const mongoOptions: MongoOptions = ({ srv, hosts } as unknown) as MongoOptions; + // TODO(NODE-2699): option parse logic + return Object.freeze(mongoOptions); +} From 21efcba9e570672ceb1b573f982af64ee3c6745a Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Mon, 9 Nov 2020 17:46:42 -0500 Subject: [PATCH 2/6] fix failing tests, silence error --- src/mongo_client_options.ts | 19 ++++++++++++------- test/functional/connection.test.js | 4 ++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/mongo_client_options.ts b/src/mongo_client_options.ts index 1775779a5d9..9da28a96573 100644 --- a/src/mongo_client_options.ts +++ b/src/mongo_client_options.ts @@ -18,7 +18,7 @@ import { URL } from 'url'; * @internal */ export interface MongoOptions - extends BSONSerializeOptions, + extends Required, Omit, Omit { hosts: { host: string; port: number }[]; @@ -110,7 +110,7 @@ const HOSTS_RX = new RegExp( export function parseURI(uri: string): { srv: boolean; url: URL; hosts: string[] } { const match = uri.match(HOSTS_RX); if (!match) { - throw new MongoParseError('Invalid connection string'); + throw new MongoParseError(`Invalid connection string ${uri}`); } // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-expect-error @@ -131,9 +131,14 @@ export function parseOptions( // eslint-disable-next-line @typescript-eslint/no-unused-vars options: MongoClientOptions = {} ): Readonly { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { srv, url, hosts } = parseURI(uri); - const mongoOptions: MongoOptions = ({ srv, hosts } as unknown) as MongoOptions; - // TODO(NODE-2699): option parse logic - return Object.freeze(mongoOptions); + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { srv, url, hosts } = parseURI(uri); + const mongoOptions: MongoOptions = ({ srv, hosts } as unknown) as MongoOptions; + // TODO(NODE-2699): option parse logic + return Object.freeze(mongoOptions); + } catch { + return Object.freeze({} as MongoOptions); + } } + diff --git a/test/functional/connection.test.js b/test/functional/connection.test.js index 403d5ef4453..302e3a4532c 100644 --- a/test/functional/connection.test.js +++ b/test/functional/connection.test.js @@ -39,8 +39,8 @@ describe('Connection', function () { ); client.connect(function (err, client) { - var db = client.db(configuration.db); expect(err).to.not.exist; + var db = client.db(configuration.db); db.collection('domainSocketCollection0').insert({ a: 1 }, { w: 1 }, function (err) { expect(err).to.not.exist; @@ -103,8 +103,8 @@ describe('Connection', function () { ); client.connect(function (err, client) { - var db = client.db(configuration.db); expect(err).to.not.exist; + var db = client.db(configuration.db); db.collection('domainSocketCollection1').insert({ x: 1 }, { w: 1 }, function (err) { expect(err).to.not.exist; From cb748a382e8ea85f84383a9e4a25453490f94aff Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Tue, 10 Nov 2020 10:59:52 -0500 Subject: [PATCH 3/6] lint --- src/mongo_client_options.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mongo_client_options.ts b/src/mongo_client_options.ts index 9da28a96573..bfc044a0d9b 100644 --- a/src/mongo_client_options.ts +++ b/src/mongo_client_options.ts @@ -141,4 +141,3 @@ export function parseOptions( return Object.freeze({} as MongoOptions); } } - From 84c8b85f0471ea1f83803bf17b6d2ddc698afebf Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 12 Nov 2020 15:31:17 -0500 Subject: [PATCH 4/6] Pick options off of MongoClientOptions --- src/mongo_client.ts | 2 +- src/mongo_client_options.ts | 122 +++++++++++++++++------------------- 2 files changed, 60 insertions(+), 64 deletions(-) diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 163ddb760b2..0c6fd846c72 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -81,7 +81,7 @@ export interface MongoURIOptions extends Pick, Omit, - Omit { + Omit, + Required< + Pick< + MongoClientOptions, + | 'autoEncryption' + | 'compression' + | 'compressors' + | 'connectTimeoutMS' + | 'dbName' + | 'directConnection' + | 'domainsEnabled' + | 'driverInfo' + | 'forceServerObjectId' + | 'gssapiServiceName' + | 'ha' + | 'haInterval' + | 'heartbeatFrequencyMS' + | 'keepAlive' + | 'keepAliveInitialDelay' + | 'localThresholdMS' + | 'logger' + | 'maxIdleTimeMS' + | 'maxPoolSize' + | 'minPoolSize' + | 'monitorCommands' + | 'noDelay' + | 'numberOfRetries' + | 'pkFactory' + | 'promiseLibrary' + | 'raw' + | 'reconnectInterval' + | 'reconnectTries' + | 'replicaSet' + | 'retryReads' + | 'retryWrites' + | 'serverSelectionTimeoutMS' + | 'serverSelectionTryOnce' + | 'socketTimeoutMS' + | 'tlsAllowInvalidCertificates' + | 'tlsAllowInvalidHostnames' + | 'tlsInsecure' + | 'waitQueueMultiple' + | 'waitQueueTimeoutMS' + | 'zlibCompressionLevel' + > + > { hosts: { host: string; port: number }[]; srv: boolean; - - autoEncryption: AutoEncryptionOptions; credentials: MongoCredentials; - compression: CompressorName; - compressors: CompressorName[]; - connectTimeoutMS: number; - dbName: string; - directConnection: boolean; - domainsEnabled: boolean; - driverInfo: DriverInfo; - forceServerObjectId: boolean; - gssapiServiceName: string; - ha: boolean; - haInterval: number; - heartbeatFrequencyMS: number; - keepAlive: boolean; - keepAliveInitialDelay: number; - localThresholdMS: number; - logger: Logger; - maxIdleTimeMS: number; - - // poolSize: number; - maxPoolSize: number; - - maxStalenessSeconds: number; - - // minSize: number; - minPoolSize: number; - - monitorCommands: boolean; - noDelay: boolean; - numberOfRetries: number; - pkFactory: PkFactory; - promiseLibrary: PromiseConstructorLike; - raw: boolean; - readConcern: ReadConcern; readPreference: ReadPreference; - reconnectInterval: number; - reconnectTries: number; - replicaSet: string; - retryReads: boolean; - retryWrites: boolean; - serverSelectionTimeoutMS: number; - serverSelectionTryOnce: boolean; - socketTimeoutMS: number; + readConcern: ReadConcern; + writeConcern: WriteConcern; /** + * # NOTE ABOUT TLS Options + * * If set TLS enabled, equivalent to setting the ssl option. * * ### Additional options: * - * | nodejs option | MongoDB equivalent | type | - * |:---------------------|----------------------------------------------------|:---------------------------------------| - * | `ca` | sslCA, tlsCAFile | `string \| Buffer \| Buffer[]` | - * | `crl` | sslCRL | `string \| Buffer \| Buffer[]` | - * | `cert` | sslCert, tlsCertificateFile, tlsCertificateKeyFile | `string \| Buffer \| Buffer[]` | - * | `key` | sslKey, tlsCertificateKeyFile | `string \| Buffer \| KeyObject[]` | - * | `passphrase` | sslPass, tlsCertificateKeyFilePassword | `string` | - * | `rejectUnauthorized` | sslValidate | `boolean` | + * | nodejs option | MongoDB equivalent | type | + * |:---------------------|--------------------------------------------------------- |:---------------------------------------| + * | `ca` | `sslCA`, `tlsCAFile` | `string \| Buffer \| Buffer[]` | + * | `crl` | `sslCRL` | `string \| Buffer \| Buffer[]` | + * | `cert` | `sslCert`, `tlsCertificateFile`, `tlsCertificateKeyFile` | `string \| Buffer \| Buffer[]` | + * | `key` | `sslKey`, `tlsCertificateKeyFile` | `string \| Buffer \| KeyObject[]` | + * | `passphrase` | `sslPass`, `tlsCertificateKeyFilePassword` | `string` | + * | `rejectUnauthorized` | `sslValidate` | `boolean` | * */ tls: boolean; - tlsAllowInvalidCertificates: boolean; - tlsAllowInvalidHostnames: boolean; - tlsInsecure: boolean; - waitQueueMultiple: number; - waitQueueTimeoutMS: number; - writeConcern: WriteConcern; - zlibCompressionLevel: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | undefined; /** * Turn these options into a reusable options dictionary */ From 852eb2412b3ee70694d408f35970b8905cd72f8b Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Fri, 13 Nov 2020 14:13:45 -0500 Subject: [PATCH 5/6] Clearer ternary statement --- src/mongo_client_options.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/mongo_client_options.ts b/src/mongo_client_options.ts index 0e03ed41992..bd6aa60e6c6 100644 --- a/src/mongo_client_options.ts +++ b/src/mongo_client_options.ts @@ -103,18 +103,23 @@ const HOSTS_RX = new RegExp( '(?mongodb(?:\\+srv|)):\\/\\/(?:(?[^:]*)(?::(?[^@]*))?@)?(?[^\\/?]*)(?.*)' ); -export function parseURI(uri: string): { srv: boolean; url: URL; hosts: string[] } { +function parseURI(uri: string): { srv: boolean; url: URL; hosts: string[] } { const match = uri.match(HOSTS_RX); if (!match) { throw new MongoParseError(`Invalid connection string ${uri}`); } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-expect-error - const { protocol, username, password, hosts, rest } = match.groups; + + const protocol = match.groups?.protocol; + const username = match.groups?.username; + const password = match.groups?.password; + const hosts = match.groups?.hosts; + const rest = match.groups?.rest; + if (!protocol || !hosts) { throw new MongoParseError('Invalid connection string, protocol and host(s) required'); } - const authString = `${username ? `${password ? `${username}:${password}` : username}` : ''}`; + + const authString = username ? (password ? `${username}:${password}` : `${username}`) : ''; return { srv: protocol.includes('srv'), url: new URL(`${protocol.toLowerCase()}://${authString}@dummyHostname${rest}`), From 956b500fd2985dad5fe5b7b79d392bc8ce7293a2 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 18 Nov 2020 12:31:17 -0500 Subject: [PATCH 6/6] Move around code --- package-lock.json | 142 ++++++++++++++++++++++------------- package.json | 8 +- src/connection_string.ts | 48 ++++++++++++ src/index.ts | 1 - src/mongo_client.ts | 94 ++++++++++++++++++++++- src/mongo_client_options.ts | 144 ------------------------------------ 6 files changed, 234 insertions(+), 203 deletions(-) delete mode 100644 src/mongo_client_options.ts diff --git a/package-lock.json b/package-lock.json index 4adfcc4bd3c..505e4a45b7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -312,16 +312,16 @@ "dev": true }, "@microsoft/api-extractor": { - "version": "7.11.2", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.11.2.tgz", - "integrity": "sha512-iZPv22j9K02cbwIDblOgF1MxZG+KWovp3CQpWCD6UC/+YYO4DfLxX5uZYVNzfgT4vU8fN0rugJmGm85rHX6Ouw==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.12.0.tgz", + "integrity": "sha512-YDd7AUkIayPLooMasDyV4vle1TLUQhFp2v/tGdRU+WAVbnyVUDXXa20WEfbPEZ4QVlgN+77EX6f2K6GyKd713A==", "dev": true, "requires": { - "@microsoft/api-extractor-model": "7.10.8", + "@microsoft/api-extractor-model": "7.12.0", "@microsoft/tsdoc": "0.12.19", - "@rushstack/node-core-library": "3.34.7", - "@rushstack/rig-package": "0.2.7", - "@rushstack/ts-command-line": "4.7.6", + "@rushstack/node-core-library": "3.35.1", + "@rushstack/rig-package": "0.2.8", + "@rushstack/ts-command-line": "4.7.7", "colors": "~1.2.1", "lodash": "~4.17.15", "resolve": "~1.17.0", @@ -335,23 +335,17 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true - }, - "typescript": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", - "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", - "dev": true } } }, "@microsoft/api-extractor-model": { - "version": "7.10.8", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.10.8.tgz", - "integrity": "sha512-9TfiCTPnkUeLaYywZeg9rYbVPX9Tj6AAkO6ThnjSE0tTPLjMcL3RiHkqn0BJ4+aGcl56APwo32zj5+kG+NqxYA==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.12.0.tgz", + "integrity": "sha512-TxoAbL/lauS3k/brBWVsiQTnyHBwHrAGJhTuiD0tWS/eu4dLNULchcSQfcOaFS91OgDEz4lMMbClgChFuo+53Q==", "dev": true, "requires": { "@microsoft/tsdoc": "0.12.19", - "@rushstack/node-core-library": "3.34.7" + "@rushstack/node-core-library": "3.35.1" } }, "@microsoft/tsdoc": { @@ -361,21 +355,21 @@ "dev": true }, "@microsoft/tsdoc-config": { - "version": "0.13.5", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.13.5.tgz", - "integrity": "sha512-KlnIdTRnPSsU9Coz9wzDAkT8JCLopP3ec1sgsgo7trwE6QLMKRpM4hZi2uzVX897SW49Q4f439auGBcQLnZQfA==", + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.13.6.tgz", + "integrity": "sha512-VJjV35PnrNISoX2WMemZjnCIdOUPTRpCz6pu8inISotLd3SgoDSJygGaE7+lOYdCtDl+4c8PWJdZivxxXgOnLw==", "dev": true, "requires": { - "@microsoft/tsdoc": "0.12.20", + "@microsoft/tsdoc": "0.12.21", "ajv": "~6.12.3", "jju": "~1.4.0", "resolve": "~1.12.0" }, "dependencies": { "@microsoft/tsdoc": { - "version": "0.12.20", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.12.20.tgz", - "integrity": "sha512-/b13m37QZYPV6nCOiqkFyvlQjlTNvAcQpgFZ6ZKIqtStJxNdqVo/frULubxMUMWi6p9Uo5f4BRlguv5ViFcL0A==", + "version": "0.12.21", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.12.21.tgz", + "integrity": "sha512-j+9OJ0A0buZZaUn6NxeHUVpoa05tY2PgVs7kXJhJQiKRB0G1zQqbJxer3T7jWtzpqQWP89OBDluyIeyTsMk8Sg==", "dev": true }, "resolve": { @@ -390,9 +384,9 @@ } }, "@rushstack/node-core-library": { - "version": "3.34.7", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.34.7.tgz", - "integrity": "sha512-7FwJ0jmZsh7bDIZ1IqDNphY9Kc6aAi1D2K8jiq+da4flMyL84HNeq2KxvwFLzjLwu3eMr88X+oBpgxCTD5Y57Q==", + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.35.1.tgz", + "integrity": "sha512-ZwnXp2loZyVUgrZ+fEKKF/EHl0ikcy6SCsd34ewYXoEAs0XWIy2VS9bemrfaFtd2VzJ/G/ZbP3xHkqRnUPKJ4Q==", "dev": true, "requires": { "@types/node": "10.17.13", @@ -421,9 +415,9 @@ } }, "@rushstack/rig-package": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.2.7.tgz", - "integrity": "sha512-hI1L0IIzCHqH/uW64mKqEQ0/MANA/IklVId3jGpj1kt9RJcBdeNUIlzDtHl437LZRAuEA8CyotRHzG6YDgWlTw==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.2.8.tgz", + "integrity": "sha512-Ltjeg1a5Sx7XTW9oBxmcfhHseBLnH7I/8d6tAtjx5s0r7F6WmNVJdxVmt86qNfXcFRsiGNrzLqjMwlcX3GyldQ==", "dev": true, "requires": { "@types/node": "10.17.13", @@ -440,9 +434,9 @@ } }, "@rushstack/ts-command-line": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.7.6.tgz", - "integrity": "sha512-falJVNfpJtsL3gJaY77JXXycfzhzB9VkKhqEfjRWD69/f6ezMUorPR6Nc90MnIaWgePTcdTJPZibxOQrNpu1Uw==", + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.7.7.tgz", + "integrity": "sha512-COSDys0WTVCORKam2hsTL32As4fHAf1RqC6FKS98hgR0Z90nh1JX8fGNkvSdxaZ6dOuNTJj3txh+SpWoHJoZJA==", "dev": true, "requires": { "@types/argparse": "1.0.38", @@ -2389,6 +2383,27 @@ "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.12.20.tgz", "integrity": "sha512-/b13m37QZYPV6nCOiqkFyvlQjlTNvAcQpgFZ6ZKIqtStJxNdqVo/frULubxMUMWi6p9Uo5f4BRlguv5ViFcL0A==", "dev": true + }, + "@microsoft/tsdoc-config": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.13.5.tgz", + "integrity": "sha512-KlnIdTRnPSsU9Coz9wzDAkT8JCLopP3ec1sgsgo7trwE6QLMKRpM4hZi2uzVX897SW49Q4f439auGBcQLnZQfA==", + "dev": true, + "requires": { + "@microsoft/tsdoc": "0.12.20", + "ajv": "~6.12.3", + "jju": "~1.4.0", + "resolve": "~1.12.0" + } + }, + "resolve": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.3.tgz", + "integrity": "sha512-hF6+hAPlxjqHWrw4p1rF3Wztbgxd4AjA5VlUzY5zcTb4J8D3JK4/1RjU48pHz2PJWzGVsLB1VWZkvJzhK2CCOA==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } } } }, @@ -3457,9 +3472,9 @@ "dev": true }, "highlight.js": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.2.tgz", - "integrity": "sha512-Q39v/Mn5mfBlMff9r+zzA+gWxRsCRKwEMvYTiisLr/XUiFI/4puWt0Ojdko3R3JCNWGdOWaA5g/Yxqa23kC5AA==", + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.3.2.tgz", + "integrity": "sha512-3jRT7OUYsVsKvukNKZCtnvRcFyCJqSEIuIMsEybAXRiFSwpt65qjPd/Pr+UOdYt7WJlt+lj3+ypUsHiySBp/Jw==", "dev": true }, "hosted-git-info": { @@ -7150,21 +7165,22 @@ } }, "typedoc": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.18.0.tgz", - "integrity": "sha512-UgDQwapCGQCCdYhEQzQ+kGutmcedklilgUGf62Vw6RdI29u6FcfAXFQfRTiJEbf16aK3YnkB20ctQK1JusCRbA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.19.2.tgz", + "integrity": "sha512-oDEg1BLEzi1qvgdQXc658EYgJ5qJLVSeZ0hQ57Eq4JXy6Vj2VX4RVo18qYxRWz75ifAaYuYNBUCnbhjd37TfOg==", "dev": true, "requires": { "fs-extra": "^9.0.1", "handlebars": "^4.7.6", - "highlight.js": "^10.0.0", - "lodash": "^4.17.15", - "lunr": "^2.3.8", + "highlight.js": "^10.2.0", + "lodash": "^4.17.20", + "lunr": "^2.3.9", "marked": "^1.1.1", "minimatch": "^3.0.0", "progress": "^2.0.3", + "semver": "^7.3.2", "shelljs": "^0.8.4", - "typedoc-default-themes": "^0.10.2" + "typedoc-default-themes": "^0.11.4" }, "dependencies": { "fs-extra": { @@ -7180,19 +7196,39 @@ } }, "jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { "graceful-fs": "^4.1.6", - "universalify": "^1.0.0" + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } } }, "marked": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-1.1.1.tgz", - "integrity": "sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.4.tgz", + "integrity": "sha512-6x5TFGCTKSQBLTZtOburGxCxFEBJEGYVLwCMTBCxzvyuisGcC20UNzDSJhCr/cJ/Kmh6ulfJm10g6WWEAJ3kvg==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "typedoc-default-themes": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.11.4.tgz", + "integrity": "sha512-Y4Lf+qIb9NTydrexlazAM46SSLrmrQRqWiD52593g53SsmUFioAsMWt8m834J6qsp+7wHRjxCXSZeiiW5cMUdw==", "dev": true }, "universalify": { @@ -7223,9 +7259,9 @@ } }, "typescript": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", - "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", + "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", "dev": true }, "typescript-cached-transpile": { diff --git a/package.json b/package.json index 0d26cd48850..012b1ea0a9f 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,8 @@ }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", - "@microsoft/api-extractor": "^7.11.2", - "@microsoft/tsdoc-config": "^0.13.5", + "@microsoft/api-extractor": "^7.12.0", + "@microsoft/tsdoc-config": "^0.13.6", "@types/aws4": "^1.5.1", "@types/bl": "^2.1.0", "@types/bson": "^4.0.2", @@ -71,9 +71,9 @@ "standard-version": "^7.1.0", "through2": "^3.0.1", "ts-node": "^9.0.0", - "typedoc": "^0.18.0", + "typedoc": "^0.19.2", "typedoc-plugin-pages": "^1.0.1", - "typescript": "^4.0.2", + "typescript": "^4.0.5", "typescript-cached-transpile": "^0.0.6", "worker-farm": "^1.5.0", "wtfnode": "^0.8.2", diff --git a/src/connection_string.ts b/src/connection_string.ts index 2e9d8bdd270..fa3ee8dd4df 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -1,12 +1,14 @@ import * as url from 'url'; import * as qs from 'querystring'; import * as dns from 'dns'; +import { URL } from 'url'; import { ReadPreference } from './read_preference'; import { MongoParseError } from './error'; import type { AnyOptions, Callback } from './utils'; import type { ConnectionOptions } from './cmap/connection'; import type { Document } from './bson'; import type { CompressorName } from './cmap/wire_protocol/compression'; +import type { MongoClientOptions, MongoOptions } from './mongo_client'; /** * The following regular expression validates a connection string and breaks the @@ -760,3 +762,49 @@ export function parseConnectionString( callback(undefined, result); } + +// NEW PARSER WORK... + +const HOSTS_REGEX = new RegExp( + '(?mongodb(?:\\+srv|)):\\/\\/(?:(?[^:]*)(?::(?[^@]*))?@)?(?[^\\/?]*)(?.*)' +); + +function parseURI(uri: string): { srv: boolean; url: URL; hosts: string[] } { + const match = uri.match(HOSTS_REGEX); + if (!match) { + throw new MongoParseError(`Invalid connection string ${uri}`); + } + + const protocol = match.groups?.protocol; + const username = match.groups?.username; + const password = match.groups?.password; + const hosts = match.groups?.hosts; + const rest = match.groups?.rest; + + if (!protocol || !hosts) { + throw new MongoParseError('Invalid connection string, protocol and host(s) required'); + } + + const authString = username ? (password ? `${username}:${password}` : `${username}`) : ''; + return { + srv: protocol.includes('srv'), + url: new URL(`${protocol.toLowerCase()}://${authString}@dummyHostname${rest}`), + hosts: hosts.split(',') + }; +} + +export function parseOptions( + uri: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options: MongoClientOptions = {} +): Readonly { + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { srv, url, hosts } = parseURI(uri); + const mongoOptions: MongoOptions = ({ srv, hosts } as unknown) as MongoOptions; + // TODO(NODE-2699): option parse logic + return Object.freeze(mongoOptions); + } catch { + return Object.freeze({} as MongoOptions); + } +} diff --git a/src/index.ts b/src/index.ts index 074e433783a..ffcc9e67339 100644 --- a/src/index.ts +++ b/src/index.ts @@ -296,4 +296,3 @@ export type { ClientMetadataOptions } from './utils'; export type { WriteConcern, W, WriteConcernOptions } from './write_concern'; -export type { MongoOptions } from './mongo_client_options'; diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 0c6fd846c72..88b4e6a9765 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -18,7 +18,10 @@ import type { Topology } from './sdam/topology'; import type { ClientSession, ClientSessionOptions } from './sessions'; import type { OperationParent } from './operations/command'; import type { TagSet } from './sdam/server_description'; -import { MongoOptions, parseOptions } from './mongo_client_options'; +import type { ConnectionOptions as TLSConnectionOptions } from 'tls'; +import type { TcpSocketConnectOpts as ConnectionOptions } from 'net'; +import type { MongoCredentials } from './cmap/auth/mongo_credentials'; +import { parseOptions } from './connection_string'; /** @public */ export enum LogLevel { @@ -569,3 +572,92 @@ export class MongoClient extends EventEmitter implements OperationParent { if (typeof callback === 'function') callback(undefined, true); }, 'Multiple authentication is prohibited on a connected client, please only authenticate once per MongoClient'); } + +/** + * Mongo Client Options + * @internal + */ +export interface MongoOptions + extends Required, + Omit, + Omit, + Required< + Pick< + MongoClientOptions, + | 'autoEncryption' + | 'compression' + | 'compressors' + | 'connectTimeoutMS' + | 'dbName' + | 'directConnection' + | 'domainsEnabled' + | 'driverInfo' + | 'forceServerObjectId' + | 'gssapiServiceName' + | 'ha' + | 'haInterval' + | 'heartbeatFrequencyMS' + | 'keepAlive' + | 'keepAliveInitialDelay' + | 'localThresholdMS' + | 'logger' + | 'maxIdleTimeMS' + | 'maxPoolSize' + | 'minPoolSize' + | 'monitorCommands' + | 'noDelay' + | 'numberOfRetries' + | 'pkFactory' + | 'promiseLibrary' + | 'raw' + | 'reconnectInterval' + | 'reconnectTries' + | 'replicaSet' + | 'retryReads' + | 'retryWrites' + | 'serverSelectionTimeoutMS' + | 'serverSelectionTryOnce' + | 'socketTimeoutMS' + | 'tlsAllowInvalidCertificates' + | 'tlsAllowInvalidHostnames' + | 'tlsInsecure' + | 'waitQueueMultiple' + | 'waitQueueTimeoutMS' + | 'zlibCompressionLevel' + > + > { + hosts: { host: string; port: number }[]; + srv: boolean; + credentials: MongoCredentials; + readPreference: ReadPreference; + readConcern: ReadConcern; + writeConcern: WriteConcern; + + /** + * # NOTE ABOUT TLS Options + * + * If set TLS enabled, equivalent to setting the ssl option. + * + * ### Additional options: + * + * | nodejs option | MongoDB equivalent | type | + * |:---------------------|--------------------------------------------------------- |:---------------------------------------| + * | `ca` | `sslCA`, `tlsCAFile` | `string \| Buffer \| Buffer[]` | + * | `crl` | `sslCRL` | `string \| Buffer \| Buffer[]` | + * | `cert` | `sslCert`, `tlsCertificateFile`, `tlsCertificateKeyFile` | `string \| Buffer \| Buffer[]` | + * | `key` | `sslKey`, `tlsCertificateKeyFile` | `string \| Buffer \| KeyObject[]` | + * | `passphrase` | `sslPass`, `tlsCertificateKeyFilePassword` | `string` | + * | `rejectUnauthorized` | `sslValidate` | `boolean` | + * + */ + tls: boolean; + + /** + * Turn these options into a reusable options dictionary + */ + toJSON(): Record; + /** + * Turn these options into a reusable connection URI + */ + toURI(): string; +} diff --git a/src/mongo_client_options.ts b/src/mongo_client_options.ts deleted file mode 100644 index bd6aa60e6c6..00000000000 --- a/src/mongo_client_options.ts +++ /dev/null @@ -1,144 +0,0 @@ -import type { MongoCredentials } from './cmap/auth/mongo_credentials'; -import type { MongoClientOptions } from './mongo_client'; -import type { ReadConcern } from './read_concern'; -import type { ReadPreference } from './read_preference'; -import type { WriteConcern } from './write_concern'; - -import type { ConnectionOptions as TLSConnectionOptions } from 'tls'; -import type { TcpSocketConnectOpts as ConnectionOptions } from 'net'; -import type { BSONSerializeOptions } from './bson'; -import { MongoParseError } from './error'; -import { URL } from 'url'; - -/** - * Mongo Client Options - * @internal - */ -export interface MongoOptions - extends Required, - Omit, - Omit, - Required< - Pick< - MongoClientOptions, - | 'autoEncryption' - | 'compression' - | 'compressors' - | 'connectTimeoutMS' - | 'dbName' - | 'directConnection' - | 'domainsEnabled' - | 'driverInfo' - | 'forceServerObjectId' - | 'gssapiServiceName' - | 'ha' - | 'haInterval' - | 'heartbeatFrequencyMS' - | 'keepAlive' - | 'keepAliveInitialDelay' - | 'localThresholdMS' - | 'logger' - | 'maxIdleTimeMS' - | 'maxPoolSize' - | 'minPoolSize' - | 'monitorCommands' - | 'noDelay' - | 'numberOfRetries' - | 'pkFactory' - | 'promiseLibrary' - | 'raw' - | 'reconnectInterval' - | 'reconnectTries' - | 'replicaSet' - | 'retryReads' - | 'retryWrites' - | 'serverSelectionTimeoutMS' - | 'serverSelectionTryOnce' - | 'socketTimeoutMS' - | 'tlsAllowInvalidCertificates' - | 'tlsAllowInvalidHostnames' - | 'tlsInsecure' - | 'waitQueueMultiple' - | 'waitQueueTimeoutMS' - | 'zlibCompressionLevel' - > - > { - hosts: { host: string; port: number }[]; - srv: boolean; - credentials: MongoCredentials; - readPreference: ReadPreference; - readConcern: ReadConcern; - writeConcern: WriteConcern; - - /** - * # NOTE ABOUT TLS Options - * - * If set TLS enabled, equivalent to setting the ssl option. - * - * ### Additional options: - * - * | nodejs option | MongoDB equivalent | type | - * |:---------------------|--------------------------------------------------------- |:---------------------------------------| - * | `ca` | `sslCA`, `tlsCAFile` | `string \| Buffer \| Buffer[]` | - * | `crl` | `sslCRL` | `string \| Buffer \| Buffer[]` | - * | `cert` | `sslCert`, `tlsCertificateFile`, `tlsCertificateKeyFile` | `string \| Buffer \| Buffer[]` | - * | `key` | `sslKey`, `tlsCertificateKeyFile` | `string \| Buffer \| KeyObject[]` | - * | `passphrase` | `sslPass`, `tlsCertificateKeyFilePassword` | `string` | - * | `rejectUnauthorized` | `sslValidate` | `boolean` | - * - */ - tls: boolean; - - /** - * Turn these options into a reusable options dictionary - */ - toJSON(): Record; - /** - * Turn these options into a reusable connection URI - */ - toURI(): string; -} - -const HOSTS_RX = new RegExp( - '(?mongodb(?:\\+srv|)):\\/\\/(?:(?[^:]*)(?::(?[^@]*))?@)?(?[^\\/?]*)(?.*)' -); - -function parseURI(uri: string): { srv: boolean; url: URL; hosts: string[] } { - const match = uri.match(HOSTS_RX); - if (!match) { - throw new MongoParseError(`Invalid connection string ${uri}`); - } - - const protocol = match.groups?.protocol; - const username = match.groups?.username; - const password = match.groups?.password; - const hosts = match.groups?.hosts; - const rest = match.groups?.rest; - - if (!protocol || !hosts) { - throw new MongoParseError('Invalid connection string, protocol and host(s) required'); - } - - const authString = username ? (password ? `${username}:${password}` : `${username}`) : ''; - return { - srv: protocol.includes('srv'), - url: new URL(`${protocol.toLowerCase()}://${authString}@dummyHostname${rest}`), - hosts: hosts.split(',') - }; -} - -export function parseOptions( - uri: string, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - options: MongoClientOptions = {} -): Readonly { - try { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { srv, url, hosts } = parseURI(uri); - const mongoOptions: MongoOptions = ({ srv, hosts } as unknown) as MongoOptions; - // TODO(NODE-2699): option parse logic - return Object.freeze(mongoOptions); - } catch { - return Object.freeze({} as MongoOptions); - } -}