CoolFace
Apppublic

opusdev/vector-similarity-api

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes
mongo_client.ts1188 linesDownload Raw Back to src
1import { promises as fs } from 'fs';2import type { TcpNetConnectOpts } from 'net';3import type { ConnectionOptions as TLSConnectionOptions, TLSSocketOptions } from 'tls';4 5import { type ServerCommandOptions, type TimeoutContext } from '.';6import { type BSONSerializeOptions, type Document, resolveBSONOptions } from './bson';7import { ChangeStream, type ChangeStreamDocument, type ChangeStreamOptions } from './change_stream';8import type { AutoEncrypter, AutoEncryptionOptions } from './client-side-encryption/auto_encrypter';9import {10  type AuthMechanismProperties,11  DEFAULT_ALLOWED_HOSTS,12  type MongoCredentials13} from './cmap/auth/mongo_credentials';14import { type TokenCache } from './cmap/auth/mongodb_oidc/token_cache';15import { AuthMechanism } from './cmap/auth/providers';16import type { LEGAL_TCP_SOCKET_OPTIONS, LEGAL_TLS_SOCKET_OPTIONS } from './cmap/connect';17import type { Connection } from './cmap/connection';18import {19  addContainerMetadata,20  type ClientMetadata,21  isDriverInfoEqual,22  makeClientMetadata23} from './cmap/handshake/client_metadata';24import type { CompressorName } from './cmap/wire_protocol/compression';25import { MongoDBResponse } from './cmap/wire_protocol/responses';26import { parseOptions, resolveSRVRecord } from './connection_string';27import { MONGO_CLIENT_EVENTS } from './constants';28import { type AbstractCursor } from './cursor/abstract_cursor';29import { Db, type DbOptions } from './db';30import type { Encrypter } from './encrypter';31import { MongoInvalidArgumentError } from './error';32import { MongoClientAuthProviders } from './mongo_client_auth_providers';33import {34  type LogComponentSeveritiesClientOptions,35  type MongoDBLogWritable,36  MongoLogger,37  type MongoLoggerOptions,38  SeverityLevel39} from './mongo_logger';40import { TypedEventEmitter } from './mongo_types';41import {42  type ClientBulkWriteModel,43  type ClientBulkWriteOptions,44  type ClientBulkWriteResult45} from './operations/client_bulk_write/common';46import { ClientBulkWriteExecutor } from './operations/client_bulk_write/executor';47import { executeOperation } from './operations/execute_operation';48import { AbstractOperation } from './operations/operation';49import type { ReadConcern, ReadConcernLevel, ReadConcernLike } from './read_concern';50import { ReadPreference, type ReadPreferenceMode } from './read_preference';51import { type AsyncDisposable, configureResourceManagement } from './resource_management';52import type { ServerMonitoringMode } from './sdam/monitor';53import type { TagSet } from './sdam/server_description';54import { readPreferenceServerSelector } from './sdam/server_selection';55import type { SrvPoller } from './sdam/srv_polling';56import { Topology, type TopologyEvents } from './sdam/topology';57import { ClientSession, type ClientSessionOptions, ServerSessionPool } from './sessions';58import {59  COSMOS_DB_CHECK,60  COSMOS_DB_MSG,61  DOCUMENT_DB_CHECK,62  DOCUMENT_DB_MSG,63  type HostAddress,64  hostMatchesWildcards,65  isHostMatch,66  MongoDBNamespace,67  noop,68  ns,69  resolveOptions,70  squashError71} from './utils';72import type { W, WriteConcern, WriteConcernSettings } from './write_concern';73 74/** @public */75export const ServerApiVersion = Object.freeze({76  v1: '1'77} as const);78 79/** @public */80export type ServerApiVersion = (typeof ServerApiVersion)[keyof typeof ServerApiVersion];81 82/** @public */83export interface ServerApi {84  version: ServerApiVersion;85  strict?: boolean;86  deprecationErrors?: boolean;87}88 89/** @public */90export interface DriverInfo {91  name?: string;92  version?: string;93  platform?: string;94}95 96/** @public */97export interface Auth {98  /** The username for auth */99  username?: string;100  /** The password for auth */101  password?: string;102}103 104/** @public */105export interface PkFactory {106  createPk(): any;107}108 109/** @public */110export type SupportedTLSConnectionOptions = Pick<111  TLSConnectionOptions & {112    allowPartialTrustChain?: boolean;113  },114  (typeof LEGAL_TLS_SOCKET_OPTIONS)[number]115>;116 117/** @public */118export type SupportedTLSSocketOptions = Pick<119  TLSSocketOptions,120  Extract<keyof TLSSocketOptions, (typeof LEGAL_TLS_SOCKET_OPTIONS)[number]>121>;122 123/** @public */124export type SupportedSocketOptions = Pick<125  TcpNetConnectOpts & {126    autoSelectFamily?: boolean;127    autoSelectFamilyAttemptTimeout?: number;128    /** Node.JS socket option to set the time the first keepalive probe is sent on an idle socket. Defaults to 120000ms */129    keepAliveInitialDelay?: number;130  },131  (typeof LEGAL_TCP_SOCKET_OPTIONS)[number]132>;133 134/** @public */135export type SupportedNodeConnectionOptions = SupportedTLSConnectionOptions &136  SupportedTLSSocketOptions &137  SupportedSocketOptions;138 139/**140 * Describes all possible URI query options for the mongo client141 * @public142 * @see https://www.mongodb.com/docs/manual/reference/connection-string143 */144export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeConnectionOptions {145  /** Specifies the name of the replica set, if the mongod is a member of a replica set. */146  replicaSet?: string;147  /**148   * @experimental149   * Specifies the time an operation will run until it throws a timeout error150   */151  timeoutMS?: number;152  /** Enables or disables TLS/SSL for the connection. */153  tls?: boolean;154  /** A boolean to enable or disables TLS/SSL for the connection. (The ssl option is equivalent to the tls option.) */155  ssl?: boolean;156  /** Specifies the location of a local .pem file that contains either the client's TLS/SSL certificate and key. */157  tlsCertificateKeyFile?: string;158  /** Specifies the password to de-crypt the tlsCertificateKeyFile. */159  tlsCertificateKeyFilePassword?: string;160  /** Specifies the location of a local .pem file that contains the root certificate chain from the Certificate Authority. This file is used to validate the certificate presented by the mongod/mongos instance. */161  tlsCAFile?: string;162  /** Specifies the location of a local CRL .pem file that contains the client revokation list. */163  tlsCRLFile?: string;164  /** Bypasses validation of the certificates presented by the mongod/mongos instance */165  tlsAllowInvalidCertificates?: boolean;166  /** Disables hostname validation of the certificate presented by the mongod/mongos instance. */167  tlsAllowInvalidHostnames?: boolean;168  /** Disables various certificate validations. */169  tlsInsecure?: boolean;170  /** The time in milliseconds to attempt a connection before timing out. */171  connectTimeoutMS?: number;172  /** The time in milliseconds to attempt a send or receive on a socket before the attempt times out. */173  socketTimeoutMS?: number;174  /** An array or comma-delimited string of compressors to enable network compression for communication between this client and a mongod/mongos instance. */175  compressors?: CompressorName[] | string;176  /** An integer that specifies the compression level if using zlib for network compression. */177  zlibCompressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | undefined;178  /** The maximum number of hosts to connect to when using an srv connection string, a setting of `0` means unlimited hosts */179  srvMaxHosts?: number;180  /**181   * Modifies the srv URI to look like:182   *183   * `_{srvServiceName}._tcp.{hostname}.{domainname}`184   *185   * Querying this DNS URI is expected to respond with SRV records186   */187  srvServiceName?: string;188  /** The maximum number of connections in the connection pool. */189  maxPoolSize?: number;190  /** The minimum number of connections in the connection pool. */191  minPoolSize?: number;192  /** The maximum number of connections that may be in the process of being established concurrently by the connection pool. */193  maxConnecting?: number;194  /**195   * The maximum amount of time a connection should remain idle in the connection pool before being marked idle, in milliseconds.196   * If specified, this must be a number greater than or equal to 0, where 0 means there is no limit. Defaults to 0. After this197   * time passes, the idle collection can be automatically cleaned up in the background.198   */199  maxIdleTimeMS?: number;200  /** The maximum time in milliseconds that a thread can wait for a connection to become available. */201  waitQueueTimeoutMS?: number;202  /** Specify a read concern for the collection (only MongoDB 3.2 or higher supported) */203  readConcern?: ReadConcernLike;204  /** The level of isolation */205  readConcernLevel?: ReadConcernLevel;206  /** Specifies the read preferences for this connection */207  readPreference?: ReadPreferenceMode | ReadPreference;208  /** Specifies, in seconds, how stale a secondary can be before the client stops using it for read operations. */209  maxStalenessSeconds?: number;210  /** Specifies the tags document as a comma-separated list of colon-separated key-value pairs.  */211  readPreferenceTags?: TagSet[];212  /** The auth settings for when connection to server. */213  auth?: Auth;214  /** Specify the database name associated with the user’s credentials. */215  authSource?: string;216  /** Specify the authentication mechanism that MongoDB will use to authenticate the connection. */217  authMechanism?: AuthMechanism;218  /** Specify properties for the specified authMechanism as a comma-separated list of colon-separated key-value pairs. */219  authMechanismProperties?: AuthMechanismProperties;220  /** The size (in milliseconds) of the latency window for selecting among multiple suitable MongoDB instances. */221  localThresholdMS?: number;222  /** Specifies how long (in milliseconds) to block for server selection before throwing an exception.  */223  serverSelectionTimeoutMS?: number;224  /** heartbeatFrequencyMS controls when the driver checks the state of the MongoDB deployment. Specify the interval (in milliseconds) between checks, counted from the end of the previous check until the beginning of the next one. */225  heartbeatFrequencyMS?: number;226  /** Sets the minimum heartbeat frequency. In the event that the driver has to frequently re-check a server's availability, it will wait at least this long since the previous check to avoid wasted effort. */227  minHeartbeatFrequencyMS?: number;228  /** The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections */229  appName?: string;230  /** Enables retryable reads. */231  retryReads?: boolean;232  /** Enable retryable writes. */233  retryWrites?: boolean;234  /** Allow a driver to force a Single topology type with a connection string containing one host */235  directConnection?: boolean;236  /** Instruct the driver it is connecting to a load balancer fronting a mongos like service */237  loadBalanced?: boolean;238  /**239   * The write concern w value240   * @deprecated Please use the `writeConcern` option instead241   */242  w?: W;243  /**244   * The write concern timeout245   * @deprecated Please use the `writeConcern` option instead246   */247  wtimeoutMS?: number;248  /**249   * The journal write concern250   * @deprecated Please use the `writeConcern` option instead251   */252  journal?: boolean;253  /**254   * A MongoDB WriteConcern, which describes the level of acknowledgement255   * requested from MongoDB for write operations.256   *257   * @see https://www.mongodb.com/docs/manual/reference/write-concern/258   */259  writeConcern?: WriteConcern | WriteConcernSettings;260  /** TCP Connection no delay */261  noDelay?: boolean;262  /** Force server to assign `_id` values instead of driver */263  forceServerObjectId?: boolean;264  /** A primary key factory function for generation of custom `_id` keys */265  pkFactory?: PkFactory;266  /** Enable command monitoring for this client */267  monitorCommands?: boolean;268  /** Server API version */269  serverApi?: ServerApi | ServerApiVersion;270  /**271   * Optionally enable in-use auto encryption272   *273   * @remarks274   *  Automatic encryption is an enterprise only feature that only applies to operations on a collection. Automatic encryption is not supported for operations on a database or view, and operations that are not bypassed will result in error275   *  (see [libmongocrypt: Auto Encryption Allow-List](https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.md#libmongocrypt-auto-encryption-allow-list)). To bypass automatic encryption for all operations, set bypassAutoEncryption=true in AutoEncryptionOpts.276   *277   *  Automatic encryption requires the authenticated user to have the [listCollections privilege action](https://www.mongodb.com/docs/manual/reference/command/listCollections/#dbcmd.listCollections).278   *279   *  If a MongoClient with a limited connection pool size (i.e a non-zero maxPoolSize) is configured with AutoEncryptionOptions, a separate internal MongoClient is created if any of the following are true:280   *  - AutoEncryptionOptions.keyVaultClient is not passed.281   *  - AutoEncryptionOptions.bypassAutomaticEncryption is false.282   *283   * If an internal MongoClient is created, it is configured with the same options as the parent MongoClient except minPoolSize is set to 0 and AutoEncryptionOptions is omitted.284   */285  autoEncryption?: AutoEncryptionOptions;286  /**287   * Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver288  /* @deprecated - Will be made internal in a future major release.289   */290  driverInfo?: DriverInfo;291  /** Configures a Socks5 proxy host used for creating TCP connections. */292  proxyHost?: string;293  /** Configures a Socks5 proxy port used for creating TCP connections. */294  proxyPort?: number;295  /** Configures a Socks5 proxy username when the proxy in proxyHost requires username/password authentication. */296  proxyUsername?: string;297  /** Configures a Socks5 proxy password when the proxy in proxyHost requires username/password authentication. */298  proxyPassword?: string;299  /** Instructs the driver monitors to use a specific monitoring mode */300  serverMonitoringMode?: ServerMonitoringMode;301  /**302   * @public303   * Specifies the destination of the driver's logging. The default is stderr.304   */305  mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable;306  /**307   * @public308   * Enable logging level per component or use `default` to control any unset components.309   */310  mongodbLogComponentSeverities?: LogComponentSeveritiesClientOptions;311  /**312   * @public313   * All BSON documents are stringified to EJSON. This controls the maximum length of those strings.314   * It is defaulted to 1000.315   */316  mongodbLogMaxDocumentLength?: number;317 318  /** @internal */319  srvPoller?: SrvPoller;320  /** @internal */321  connectionType?: typeof Connection;322  /** @internal */323  __skipPingOnConnect?: boolean;324}325 326/** @public */327export type WithSessionCallback<T = unknown> = (session: ClientSession) => Promise<T>;328 329/** @internal */330export interface MongoClientPrivate {331  url: string;332  bsonOptions: BSONSerializeOptions;333  namespace: MongoDBNamespace;334  hasBeenClosed: boolean;335  authProviders: MongoClientAuthProviders;336  /**337   * We keep a reference to the sessions that are acquired from the pool.338   * - used to track and close all sessions in client.close() (which is non-standard behavior)339   * - used to notify the leak checker in our tests if test author forgot to clean up explicit sessions340   */341  readonly activeSessions: Set<ClientSession>;342  /**343   * We keep a reference to the cursors that are created from this client.344   * - used to track and close all cursors in client.close().345   *   Cursors in this set are ones that still need to have their close method invoked (no other conditions are considered)346   */347  readonly activeCursors: Set<AbstractCursor>;348  readonly sessionPool: ServerSessionPool;349  readonly options: MongoOptions;350  readonly readConcern?: ReadConcern;351  readonly writeConcern?: WriteConcern;352  readonly readPreference: ReadPreference;353  readonly isMongoClient: true;354}355 356/** @public */357export type MongoClientEvents = Pick<TopologyEvents, (typeof MONGO_CLIENT_EVENTS)[number]> & {358  // In previous versions the open event emitted a topology, in an effort to no longer359  // expose internals but continue to expose this useful event API, it now emits a mongoClient360  open(mongoClient: MongoClient): void;361};362 363/**364 * @public365 *366 * The **MongoClient** class is a class that allows for making Connections to MongoDB.367 *368 * **NOTE:** The programmatically provided options take precedence over the URI options.369 *370 * @remarks371 *372 * A MongoClient is the entry point to connecting to a MongoDB server.373 *374 * It handles a multitude of features on your application's behalf:375 * - **Server Host Connection Configuration**: A MongoClient is responsible for reading TLS cert, ca, and crl files if provided.376 * - **SRV Record Polling**: A "`mongodb+srv`" style connection string is used to have the MongoClient resolve DNS SRV records of all server hostnames which the driver periodically monitors for changes and adjusts its current view of hosts correspondingly.377 * - **Server Monitoring**: The MongoClient automatically keeps monitoring the health of server nodes in your cluster to reach out to the correct and lowest latency one available.378 * - **Connection Pooling**: To avoid paying the cost of rebuilding a connection to the server on every operation the MongoClient keeps idle connections preserved for reuse.379 * - **Session Pooling**: The MongoClient creates logical sessions that enable retryable writes, causal consistency, and transactions. It handles pooling these sessions for reuse in subsequent operations.380 * - **Cursor Operations**: A MongoClient's cursors use the health monitoring system to send the request for more documents to the same server the query began on.381 * - **Mongocryptd process**: When using auto encryption, a MongoClient will launch a `mongocryptd` instance for handling encryption if the mongocrypt shared library isn't in use.382 *383 * There are many more features of a MongoClient that are not listed above.384 *385 * In order to enable these features, a number of asynchronous Node.js resources are established by the driver: Timers, FS Requests, Sockets, etc.386 * For details on cleanup, please refer to the MongoClient `close()` documentation.387 *388 * @example389 * ```ts390 * import { MongoClient } from 'mongodb';391 * // Enable command monitoring for debugging392 * const client = new MongoClient('mongodb://localhost:27017?appName=mflix', { monitorCommands: true });393 * ```394 */395export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements AsyncDisposable {396  /** @internal */397  s: MongoClientPrivate;398  /** @internal */399  topology?: Topology;400  /** @internal */401  override readonly mongoLogger: MongoLogger | undefined;402  /** @internal */403  private connectionLock?: Promise<this>;404  /** @internal */405  private closeLock?: Promise<void>;406 407  /**408   * The consolidate, parsed, transformed and merged options.409   */410  public readonly options: Readonly<411    Omit<412      MongoOptions,413      | 'monitorCommands'414      | 'ca'415      | 'crl'416      | 'key'417      | 'cert'418      | 'driverInfo'419      | 'additionalDriverInfo'420      | 'metadata'421      | 'extendedMetadata'422    >423  > &424    Pick<425      MongoOptions,426      | 'monitorCommands'427      | 'ca'428      | 'crl'429      | 'key'430      | 'cert'431      | 'driverInfo'432      | 'additionalDriverInfo'433      | 'metadata'434      | 'extendedMetadata'435    >;436 437  private driverInfoList: DriverInfo[] = [];438 439  constructor(url: string, options?: MongoClientOptions) {440    super();441    this.on('error', noop);442 443    this.options = parseOptions(url, this, options);444 445    this.appendMetadata(this.options.driverInfo);446 447    const shouldSetLogger = Object.values(this.options.mongoLoggerOptions.componentSeverities).some(448      value => value !== SeverityLevel.OFF449    );450    this.mongoLogger = shouldSetLogger451      ? new MongoLogger(this.options.mongoLoggerOptions)452      : undefined;453 454    // eslint-disable-next-line @typescript-eslint/no-this-alias455    const client = this;456 457    // The internal state458    this.s = {459      url,460      bsonOptions: resolveBSONOptions(this.options),461      namespace: ns('admin'),462      hasBeenClosed: false,463      sessionPool: new ServerSessionPool(this),464      activeSessions: new Set(),465      activeCursors: new Set(),466      authProviders: new MongoClientAuthProviders(),467 468      get options() {469        return client.options;470      },471      get readConcern() {472        return client.options.readConcern;473      },474      get writeConcern() {475        return client.options.writeConcern;476      },477      get readPreference() {478        return client.options.readPreference;479      },480      get isMongoClient(): true {481        return true;482      }483    };484    this.checkForNonGenuineHosts();485  }486 487  /**488   * @beta489   * @experimental490   * An alias for {@link MongoClient.close|MongoClient.close()}.491   */492  declare [Symbol.asyncDispose]: () => Promise<void>;493  /** @internal */494  async asyncDispose() {495    await this.close();496  }497 498  /**499   * Append metadata to the client metadata after instantiation.500   * @param driverInfo - Information about the application or library.501   */502  appendMetadata(driverInfo: DriverInfo) {503    const isDuplicateDriverInfo = this.driverInfoList.some(info =>504      isDriverInfoEqual(info, driverInfo)505    );506    if (isDuplicateDriverInfo) return;507 508    this.driverInfoList.push(driverInfo);509    this.options.metadata = makeClientMetadata(this.driverInfoList, this.options);510    this.options.extendedMetadata = addContainerMetadata(this.options.metadata)511      .then(undefined, squashError)512      .then(result => result ?? {}); // ensure Promise<Document>513  }514 515  /** @internal */516  private checkForNonGenuineHosts() {517    const documentDBHostnames = this.options.hosts.filter((hostAddress: HostAddress) =>518      isHostMatch(DOCUMENT_DB_CHECK, hostAddress.host)519    );520    const srvHostIsDocumentDB = isHostMatch(DOCUMENT_DB_CHECK, this.options.srvHost);521 522    const cosmosDBHostnames = this.options.hosts.filter((hostAddress: HostAddress) =>523      isHostMatch(COSMOS_DB_CHECK, hostAddress.host)524    );525    const srvHostIsCosmosDB = isHostMatch(COSMOS_DB_CHECK, this.options.srvHost);526 527    if (documentDBHostnames.length !== 0 || srvHostIsDocumentDB) {528      this.mongoLogger?.info('client', DOCUMENT_DB_MSG);529    } else if (cosmosDBHostnames.length !== 0 || srvHostIsCosmosDB) {530      this.mongoLogger?.info('client', COSMOS_DB_MSG);531    }532  }533 534  get serverApi(): Readonly<ServerApi | undefined> {535    return this.options.serverApi && Object.freeze({ ...this.options.serverApi });536  }537  /**538   * Intended for APM use only539   * @internal540   */541  get monitorCommands(): boolean {542    return this.options.monitorCommands;543  }544  set monitorCommands(value: boolean) {545    this.options.monitorCommands = value;546  }547 548  /** @internal */549  get autoEncrypter(): AutoEncrypter | undefined {550    return this.options.autoEncrypter;551  }552 553  get readConcern(): ReadConcern | undefined {554    return this.s.readConcern;555  }556 557  get writeConcern(): WriteConcern | undefined {558    return this.s.writeConcern;559  }560 561  get readPreference(): ReadPreference {562    return this.s.readPreference;563  }564 565  get bsonOptions(): BSONSerializeOptions {566    return this.s.bsonOptions;567  }568 569  get timeoutMS(): number | undefined {570    return this.s.options.timeoutMS;571  }572 573  /**574   * Executes a client bulk write operation, available on server 8.0+.575   * @param models - The client bulk write models.576   * @param options - The client bulk write options.577   * @returns A ClientBulkWriteResult for acknowledged writes and ok: 1 for unacknowledged writes.578   */579  async bulkWrite<SchemaMap extends Record<string, Document> = Record<string, Document>>(580    models: ReadonlyArray<ClientBulkWriteModel<SchemaMap>>,581    options?: ClientBulkWriteOptions582  ): Promise<ClientBulkWriteResult> {583    if (this.autoEncrypter) {584      throw new MongoInvalidArgumentError(585        'MongoClient bulkWrite does not currently support automatic encryption.'586      );587    }588    // We do not need schema type information past this point ("as any" is fine)589    return await new ClientBulkWriteExecutor(590      this,591      models as any,592      resolveOptions(this, options)593    ).execute();594  }595 596  /**597   * Connect to MongoDB using a url598   *599   * @remarks600   * Calling `connect` is optional since the first operation you perform will call `connect` if it's needed.601   * `timeoutMS` will bound the time any operation can take before throwing a timeout error.602   * However, when the operation being run is automatically connecting your `MongoClient` the `timeoutMS` will not apply to the time taken to connect the MongoClient.603   * This means the time to setup the `MongoClient` does not count against `timeoutMS`.604   * If you are using `timeoutMS` we recommend connecting your client explicitly in advance of any operation to avoid this inconsistent execution time.605   *606   * @remarks607   * The driver will look up corresponding SRV and TXT records if the connection string starts with `mongodb+srv://`.608   * If those look ups throw a DNS Timeout error, the driver will retry the look up once.609   *610   * @see docs.mongodb.org/manual/reference/connection-string/611   */612  async connect(): Promise<this> {613    if (this.connectionLock) {614      return await this.connectionLock;615    }616 617    try {618      this.connectionLock = this._connect();619      await this.connectionLock;620    } finally {621      // release622      this.connectionLock = undefined;623    }624 625    return this;626  }627 628  /**629   * Create a topology to open the connection, must be locked to avoid topology leaks in concurrency scenario.630   * Locking is enforced by the connect method.631   *632   * @internal633   */634  private async _connect(): Promise<this> {635    if (this.topology && this.topology.isConnected()) {636      return this;637    }638 639    const options = this.options;640 641    if (options.tls) {642      if (typeof options.tlsCAFile === 'string') {643        options.ca ??= await fs.readFile(options.tlsCAFile);644      }645      if (typeof options.tlsCRLFile === 'string') {646        options.crl ??= await fs.readFile(options.tlsCRLFile);647      }648      if (typeof options.tlsCertificateKeyFile === 'string') {649        if (!options.key || !options.cert) {650          const contents = await fs.readFile(options.tlsCertificateKeyFile);651          options.key ??= contents;652          options.cert ??= contents;653        }654      }655    }656    if (typeof options.srvHost === 'string') {657      const hosts = await resolveSRVRecord(options);658 659      for (const [index, host] of hosts.entries()) {660        options.hosts[index] = host;661      }662    }663 664    // It is important to perform validation of hosts AFTER SRV resolution, to check the real hostname,665    // but BEFORE we even attempt connecting with a potentially not allowed hostname666    if (options.credentials?.mechanism === AuthMechanism.MONGODB_OIDC) {667      const allowedHosts =668        options.credentials?.mechanismProperties?.ALLOWED_HOSTS || DEFAULT_ALLOWED_HOSTS;669      const isServiceAuth = !!options.credentials?.mechanismProperties?.ENVIRONMENT;670      if (!isServiceAuth) {671        for (const host of options.hosts) {672          if (!hostMatchesWildcards(host.toHostPort().host, allowedHosts)) {673            throw new MongoInvalidArgumentError(674              `Host '${host}' is not valid for OIDC authentication with ALLOWED_HOSTS of '${allowedHosts.join(675                ','676              )}'`677            );678          }679        }680      }681    }682 683    this.topology = new Topology(this, options.hosts, options);684    // Events can be emitted before initialization is complete so we have to685    // save the reference to the topology on the client ASAP if the event handlers need to access it686 687    this.topology.once(Topology.OPEN, () => this.emit('open', this));688 689    for (const event of MONGO_CLIENT_EVENTS) {690      this.topology.on(event, (...args: any[]) => this.emit(event, ...(args as any)));691    }692 693    const topologyConnect = async () => {694      try {695        await this.topology?.connect(options);696      } catch (error) {697        this.topology?.close();698        throw error;699      }700    };701 702    if (this.autoEncrypter) {703      await this.autoEncrypter?.init();704      await topologyConnect();705      await options.encrypter.connectInternalClient();706    } else {707      await topologyConnect();708    }709 710    return this;711  }712 713  /**714   * Cleans up resources managed by the MongoClient.715   *716   * The close method clears and closes all resources whose lifetimes are managed by the MongoClient.717   * Please refer to the `MongoClient` class documentation for a high level overview of the client's key features and responsibilities.718   *719   * **However,** the close method does not handle the cleanup of resources explicitly created by the user.720   * Any user-created driver resource with its own `close()` method should be explicitly closed by the user before calling MongoClient.close().721   * This method is written as a "best effort" attempt to leave behind the least amount of resources server-side when possible.722   *723   * The following list defines ideal preconditions and consequent pitfalls if they are not met.724   * The MongoClient, ClientSession, Cursors and ChangeStreams all support [explicit resource management](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html).725   * By using explicit resource management to manage the lifetime of driver resources instead of manually managing their lifetimes, the pitfalls outlined below can be avoided.726   *727   * The close method performs the following in the order listed:728   * - Client-side:729   *   - **Close in-use connections**: Any connections that are currently waiting on a response from the server will be closed.730   *     This is performed _first_ to avoid reaching the next step (server-side clean up) and having no available connections to check out.731   *     - _Ideal_: All operations have been awaited or cancelled, and the outcomes, regardless of success or failure, have been processed before closing the client servicing the operation.732   *     - _Pitfall_: When `client.close()` is called and all connections are in use, after closing them, the client must create new connections for cleanup operations, which comes at the cost of new TLS/TCP handshakes and authentication steps.733   * - Server-side:734   *   - **Close active cursors**: All cursors that haven't been completed will have a `killCursor` operation sent to the server they were initialized on, freeing the server-side resource.735   *     - _Ideal_: Cursors are explicitly closed or completed before `client.close()` is called.736   *     - _Pitfall_: `killCursors` may have to build a new connection if the in-use closure ended all pooled connections.737   *   - **End active sessions**: In-use sessions created with `client.startSession()` or `client.withSession()` or implicitly by the driver will have their `.endSession()` method called.738   *     Contrary to the name of the method, `endSession()` returns the session to the client's pool of sessions rather than end them on the server.739   *     - _Ideal_: Transaction outcomes are awaited and their corresponding explicit sessions are ended before `client.close()` is called.740   *     - _Pitfall_: **This step aborts in-progress transactions**. It is advisable to observe the outcome of a transaction before closing your client.741   *   - **End all pooled sessions**: The `endSessions` command with all session IDs the client has pooled is sent to the server to inform the cluster it can clean them up.742   *     - _Ideal_: No user intervention is expected.743   *     - _Pitfall_: None.744   *745   * The remaining shutdown is of the MongoClient resources that are intended to be entirely internal but is documented here as their existence relates to the JS event loop.746   *747   * - Client-side (again):748   *   - **Stop all server monitoring**: Connections kept live for detecting cluster changes and roundtrip time measurements are shutdown.749   *   - **Close all pooled connections**: Each server node in the cluster has a corresponding connection pool and all connections in the pool are closed. Any operations waiting to check out a connection will have an error thrown instead of a connection returned.750   *   - **Clear out server selection queue**: Any operations that are in the process of waiting for a server to be selected will have an error thrown instead of a server returned.751   *   - **Close encryption-related resources**: An internal MongoClient created for communicating with `mongocryptd` or other encryption purposes is closed. (Using this same method of course!)752   *753   * After the close method completes there should be no MongoClient related resources [ref-ed in Node.js' event loop](https://docs.libuv.org/en/v1.x/handle.html#reference-counting).754   * This should allow Node.js to exit gracefully if MongoClient resources were the only active handles in the event loop.755   *756   * @param _force - currently an unused flag that has no effect. Defaults to `false`.757   */758  async close(_force = false): Promise<void> {759    if (this.closeLock) {760      return await this.closeLock;761    }762 763    try {764      this.closeLock = this._close();765      await this.closeLock;766    } finally {767      // release768      this.closeLock = undefined;769    }770  }771 772  /* @internal */773  private async _close(): Promise<void> {774    // There's no way to set hasBeenClosed back to false775    Object.defineProperty(this.s, 'hasBeenClosed', {776      value: true,777      enumerable: true,778      configurable: false,779      writable: false780    });781 782    this.topology?.closeCheckedOutConnections();783 784    const activeCursorCloses = Array.from(this.s.activeCursors, cursor => cursor.close());785    this.s.activeCursors.clear();786 787    await Promise.all(activeCursorCloses);788 789    const activeSessionEnds = Array.from(this.s.activeSessions, session => session.endSession());790    this.s.activeSessions.clear();791 792    await Promise.all(activeSessionEnds);793 794    if (this.topology == null) {795      return;796    }797 798    // If we would attempt to select a server and get nothing back we short circuit799    // to avoid the server selection timeout.800    const selector = readPreferenceServerSelector(ReadPreference.primaryPreferred);801    const topologyDescription = this.topology.description;802    const serverDescriptions = Array.from(topologyDescription.servers.values());803    const servers = selector(topologyDescription, serverDescriptions);804    if (servers.length !== 0) {805      const endSessions = Array.from(this.s.sessionPool.sessions, ({ id }) => id);806      if (endSessions.length !== 0) {807        try {808          class EndSessionsOperation extends AbstractOperation<void> {809            override ns = MongoDBNamespace.fromString('admin.$cmd');810            override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;811            override buildCommand(_connection: Connection, _session?: ClientSession): Document {812              return {813                endSessions814              };815            }816            override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {817              return {818                timeoutContext,819                readPreference: ReadPreference.primaryPreferred,820                noResponse: true821              };822            }823            override get commandName(): string {824              return 'endSessions';825            }826          }827          await executeOperation(this, new EndSessionsOperation());828        } catch (error) {829          squashError(error);830        }831      }832    }833 834    // clear out references to old topology835    const topology = this.topology;836    this.topology = undefined;837 838    topology.close();839 840    const { encrypter } = this.options;841    if (encrypter) {842      await encrypter.close(this);843    }844  }845 846  /**847   * Create a new Db instance sharing the current socket connections.848   *849   * @param dbName - The name of the database we want to use. If not provided, use database name from connection string.850   * @param options - Optional settings for Db construction851   */852  db(dbName?: string, options?: DbOptions): Db {853    options = options ?? {};854 855    // Default to db from connection string if not provided856    if (!dbName) {857      dbName = this.s.options.dbName;858    }859 860    // Copy the options and add out internal override of the not shared flag861    const finalOptions = Object.assign({}, this.options, options);862 863    // Return the db object864    const db = new Db(this, dbName, finalOptions);865 866    // Return the database867    return db;868  }869 870  /**871   * Connect to MongoDB using a url872   *873   * @remarks874   * Calling `connect` is optional since the first operation you perform will call `connect` if it's needed.875   * `timeoutMS` will bound the time any operation can take before throwing a timeout error.876   * However, when the operation being run is automatically connecting your `MongoClient` the `timeoutMS` will not apply to the time taken to connect the MongoClient.877   * This means the time to setup the `MongoClient` does not count against `timeoutMS`.878   * If you are using `timeoutMS` we recommend connecting your client explicitly in advance of any operation to avoid this inconsistent execution time.879   *880   * @remarks881   * The programmatically provided options take precedence over the URI options.882   *883   * @remarks884   * The driver will look up corresponding SRV and TXT records if the connection string starts with `mongodb+srv://`.885   * If those look ups throw a DNS Timeout error, the driver will retry the look up once.886   *887   * @see https://www.mongodb.com/docs/manual/reference/connection-string/888   */889  static async connect(url: string, options?: MongoClientOptions): Promise<MongoClient> {890    const client = new this(url, options);891    return await client.connect();892  }893 894  /**895   * Creates a new ClientSession. When using the returned session in an operation896   * a corresponding ServerSession will be created.897   *898   * @remarks899   * A ClientSession instance may only be passed to operations being performed on the same900   * MongoClient it was started from.901   */902  startSession(options?: ClientSessionOptions): ClientSession {903    const session = new ClientSession(904      this,905      this.s.sessionPool,906      { explicit: true, ...options },907      this.options908    );909    this.s.activeSessions.add(session);910    session.once('ended', () => {911      this.s.activeSessions.delete(session);912    });913    return session;914  }915 916  /**917   * A convenience method for creating and handling the clean up of a ClientSession.918   * The session will always be ended when the executor finishes.919   *920   * @param executor - An executor function that all operations using the provided session must be invoked in921   * @param options - optional settings for the session922   */923  async withSession<T = any>(executor: WithSessionCallback<T>): Promise<T>;924  async withSession<T = any>(925    options: ClientSessionOptions,926    executor: WithSessionCallback<T>927  ): Promise<T>;928  async withSession<T = any>(929    optionsOrExecutor: ClientSessionOptions | WithSessionCallback<T>,930    executor?: WithSessionCallback<T>931  ): Promise<T> {932    const options = {933      // Always define an owner934      owner: Symbol(),935      // If it's an object inherit the options936      ...(typeof optionsOrExecutor === 'object' ? optionsOrExecutor : {})937    };938 939    const withSessionCallback =940      typeof optionsOrExecutor === 'function' ? optionsOrExecutor : executor;941 942    if (withSessionCallback == null) {943      throw new MongoInvalidArgumentError('Missing required callback parameter');944    }945 946    const session = this.startSession(options);947 948    try {949      return await withSessionCallback(session);950    } finally {951      try {952        await session.endSession();953      } catch (error) {954        squashError(error);955      }956    }957  }958 959  /**960   * Create a new Change Stream, watching for new changes (insertions, updates,961   * replacements, deletions, and invalidations) in this cluster. Will ignore all962   * changes to system collections, as well as the local, admin, and config databases.963   *964   * @remarks965   * watch() accepts two generic arguments for distinct use cases:966   * - The first is to provide the schema that may be defined for all the data within the current cluster967   * - The second is to override the shape of the change stream document entirely, if it is not provided the type will default to ChangeStreamDocument of the first argument968   *969   * @remarks970   * When `timeoutMS` is configured for a change stream, it will have different behaviour depending971   * on whether the change stream is in iterator mode or emitter mode. In both cases, a change972   * stream will time out if it does not receive a change event within `timeoutMS` of the last change973   * event.974   *975   * Note that if a change stream is consistently timing out when watching a collection, database or976   * client that is being changed, then this may be due to the server timing out before it can finish977   * processing the existing oplog. To address this, restart the change stream with a higher978   * `timeoutMS`.979   *980   * If the change stream times out the initial aggregate operation to establish the change stream on981   * the server, then the client will close the change stream. If the getMore calls to the server982   * time out, then the change stream will be left open, but will throw a MongoOperationTimeoutError983   * when in iterator mode and emit an error event that returns a MongoOperationTimeoutError in984   * emitter mode.985   *986   * To determine whether or not the change stream is still open following a timeout, check the987   * {@link ChangeStream.closed} getter.988   *989   * @example990   * In iterator mode, if a next() call throws a timeout error, it will attempt to resume the change stream.991   * The next call can just be retried after this succeeds.992   * ```ts993   * const changeStream = collection.watch([], { timeoutMS: 100 });994   * try {995   *     await changeStream.next();996   * } catch (e) {997   *     if (e instanceof MongoOperationTimeoutError && !changeStream.closed) {998   *       await changeStream.next();999   *     }1000   *     throw e;1001   * }1002   * ```1003   *1004   * @example1005   * In emitter mode, if the change stream goes `timeoutMS` without emitting a change event, it will1006   * emit an error event that returns a MongoOperationTimeoutError, but will not close the change1007   * stream unless the resume attempt fails. There is no need to re-establish change listeners as1008   * this will automatically continue emitting change events once the resume attempt completes.1009   *1010   * ```ts1011   * const changeStream = collection.watch([], { timeoutMS: 100 });1012   * changeStream.on('change', console.log);1013   * changeStream.on('error', e => {1014   *     if (e instanceof MongoOperationTimeoutError && !changeStream.closed) {1015   *         // do nothing1016   *     } else {1017   *         changeStream.close();1018   *     }1019   * });1020   * ```1021   * @param pipeline - An array of {@link https://www.mongodb.com/docs/manual/reference/operator/aggregation-pipeline/|aggregation pipeline stages} through which to pass change stream documents. This allows for filtering (using $match) and manipulating the change stream documents.1022   * @param options - Optional settings for the command1023   * @typeParam TSchema - Type of the data being detected by the change stream1024   * @typeParam TChange - Type of the whole change stream document emitted1025   */1026  watch<1027    TSchema extends Document = Document,1028    TChange extends Document = ChangeStreamDocument<TSchema>1029  >(pipeline: Document[] = [], options: ChangeStreamOptions = {}): ChangeStream<TSchema, TChange> {1030    // Allow optionally not specifying a pipeline1031    if (!Array.isArray(pipeline)) {1032      options = pipeline;1033      pipeline = [];1034    }1035 1036    return new ChangeStream<TSchema, TChange>(this, pipeline, resolveOptions(this, options));1037  }1038}1039 1040configureResourceManagement(MongoClient.prototype);1041 1042/**1043 * Parsed Mongo Client Options.1044 *1045 * User supplied options are documented by `MongoClientOptions`.1046 *1047 * **NOTE:** The client's options parsing is subject to change to support new features.1048 * This type is provided to aid with inspection of options after parsing, it should not be relied upon programmatically.1049 *1050 * Options are sourced from:1051 * - connection string1052 * - options object passed to the MongoClient constructor1053 * - file system (ex. tls settings)1054 * - environment variables1055 * - DNS SRV records and TXT records1056 *1057 * Not all options may be present after client construction as some are obtained from asynchronous operations.1058 *1059 * @public1060 */1061export interface MongoOptions1062  extends Required<1063      Pick<1064        MongoClientOptions,1065        | 'autoEncryption'1066        | 'connectTimeoutMS'1067        | 'directConnection'1068        | 'driverInfo'1069        | 'forceServerObjectId'1070        | 'minHeartbeatFrequencyMS'1071        | 'heartbeatFrequencyMS'1072        | 'localThresholdMS'1073        | 'maxConnecting'1074        | 'maxIdleTimeMS'1075        | 'maxPoolSize'1076        | 'minPoolSize'1077        | 'monitorCommands'1078        | 'noDelay'1079        | 'pkFactory'1080        | 'raw'1081        | 'replicaSet'1082        | 'retryReads'1083        | 'retryWrites'1084        | 'serverSelectionTimeoutMS'1085        | 'socketTimeoutMS'1086        | 'srvMaxHosts'1087        | 'srvServiceName'1088        | 'tlsAllowInvalidCertificates'1089        | 'tlsAllowInvalidHostnames'1090        | 'tlsInsecure'1091        | 'waitQueueTimeoutMS'1092        | 'zlibCompressionLevel'1093      >1094    >,1095    SupportedNodeConnectionOptions {1096  appName?: string;1097  hosts: HostAddress[];1098  srvHost?: string;1099  credentials?: MongoCredentials;1100  readPreference: ReadPreference;1101  readConcern: ReadConcern;1102  loadBalanced: boolean;1103  directConnection: boolean;1104  serverApi: ServerApi;1105  compressors: CompressorName[];1106  writeConcern: WriteConcern;1107  dbName: string;1108  /** @deprecated - Will be made internal in a future major release. */1109  metadata: ClientMetadata;1110  /** @deprecated - Will be made internal in a future major release. */1111  extendedMetadata: Promise<Document>;1112  /** @deprecated - Will be made internal in a future major release. */1113  additionalDriverInfo: DriverInfo[];1114  /** @internal */1115  autoEncrypter?: AutoEncrypter;1116  /** @internal */1117  tokenCache?: TokenCache;1118  proxyHost?: string;1119  proxyPort?: number;1120  proxyUsername?: string;1121  proxyPassword?: string;1122  serverMonitoringMode: ServerMonitoringMode;1123  /** @internal */1124  connectionType?: typeof Connection;1125  /** @internal */1126  authProviders: MongoClientAuthProviders;1127  /** @internal */1128  encrypter: Encrypter;1129  /** @internal */1130  userSpecifiedAuthSource: boolean;1131  /** @internal */1132  userSpecifiedReplicaSet: boolean;1133 1134  /**1135   * # NOTE ABOUT TLS Options1136   *1137   * If `tls` is provided as an option, it is equivalent to setting the `ssl` option.1138   *1139   * NodeJS native TLS options are passed through to the socket and retain their original types.1140   *1141   * ### Additional options:1142   *1143   * | nodejs native option  | driver spec equivalent option name            | driver option type |1144   * |:----------------------|:----------------------------------------------|:-------------------|1145   * | `ca`                  | `tlsCAFile`                                   | `string`           |1146   * | `crl`                 | `tlsCRLFile`                                  | `string`           |1147   * | `cert`                | `tlsCertificateKeyFile`                       | `string`           |1148   * | `key`                 | `tlsCertificateKeyFile`                       | `string`           |1149   * | `passphrase`          | `tlsCertificateKeyFilePassword`               | `string`           |1150   * | `rejectUnauthorized`  | `tlsAllowInvalidCertificates`                 | `boolean`          |1151   * | `checkServerIdentity` | `tlsAllowInvalidHostnames`                    | `boolean`          |1152   * | see note below        | `tlsInsecure`                                 | `boolean`          |1153   *1154   * If `tlsInsecure` is set to `true`, then it will set the node native options `checkServerIdentity`1155   * to a no-op and `rejectUnauthorized` to `false`.1156   *1157   * If `tlsInsecure` is set to `false`, then it will set the node native options `checkServerIdentity`1158   * to a no-op and `rejectUnauthorized` to the inverse value of `tlsAllowInvalidCertificates`. If1159   * `tlsAllowInvalidCertificates` is not set, then `rejectUnauthorized` will be set to `true`.1160   *1161   * ### Note on `tlsCAFile`, `tlsCertificateKeyFile` and `tlsCRLFile`1162   *1163   * The files specified by the paths passed in to the `tlsCAFile`, `tlsCertificateKeyFile` and `tlsCRLFile`1164   * fields are read lazily on the first call to `MongoClient.connect`. Once these files have been read and1165   * the `ca`, `cert`, `crl` and `key` fields are populated, they will not be read again on subsequent calls to1166   * `MongoClient.connect`. As a result, until the first call to `MongoClient.connect`, the `ca`,1167   * `cert`, `crl` and `key` fields will be undefined.1168   */1169  tls: boolean;1170  tlsCAFile?: string;1171  tlsCRLFile?: string;1172  tlsCertificateKeyFile?: string;1173 1174  /**1175   * @internal1176   * TODO: NODE-5671 - remove internal flag1177   */1178  mongoLoggerOptions: MongoLoggerOptions;1179  /**1180   * @internal1181   * TODO: NODE-5671 - remove internal flag1182   */1183  mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable;1184  timeoutMS?: number;1185  /** @internal */1186  __skipPingOnConnect?: boolean;1187}1188