mongodb 6.12.0 → 6.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/lib/beta.d.ts +176 -108
  2. package/lib/bulk/common.js +5 -7
  3. package/lib/bulk/common.js.map +1 -1
  4. package/lib/change_stream.js +16 -26
  5. package/lib/change_stream.js.map +1 -1
  6. package/lib/client-side-encryption/auto_encrypter.js +4 -2
  7. package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
  8. package/lib/client-side-encryption/client_encryption.js +4 -4
  9. package/lib/client-side-encryption/client_encryption.js.map +1 -1
  10. package/lib/client-side-encryption/state_machine.js +56 -30
  11. package/lib/client-side-encryption/state_machine.js.map +1 -1
  12. package/lib/cmap/auth/mongodb_oidc.js +1 -1
  13. package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
  14. package/lib/cmap/command_monitoring_events.js +9 -50
  15. package/lib/cmap/command_monitoring_events.js.map +1 -1
  16. package/lib/cmap/connection.js +28 -22
  17. package/lib/cmap/connection.js.map +1 -1
  18. package/lib/cmap/connection_pool.js +88 -117
  19. package/lib/cmap/connection_pool.js.map +1 -1
  20. package/lib/cmap/wire_protocol/on_data.js +6 -1
  21. package/lib/cmap/wire_protocol/on_data.js.map +1 -1
  22. package/lib/collection.js.map +1 -1
  23. package/lib/connection_string.js +68 -86
  24. package/lib/connection_string.js.map +1 -1
  25. package/lib/cursor/abstract_cursor.js +47 -18
  26. package/lib/cursor/abstract_cursor.js.map +1 -1
  27. package/lib/cursor/aggregation_cursor.js +2 -1
  28. package/lib/cursor/aggregation_cursor.js.map +1 -1
  29. package/lib/cursor/find_cursor.js +2 -1
  30. package/lib/cursor/find_cursor.js.map +1 -1
  31. package/lib/cursor/list_collections_cursor.js +2 -1
  32. package/lib/cursor/list_collections_cursor.js.map +1 -1
  33. package/lib/db.js +2 -1
  34. package/lib/db.js.map +1 -1
  35. package/lib/encrypter.js +5 -9
  36. package/lib/encrypter.js.map +1 -1
  37. package/lib/error.js +10 -18
  38. package/lib/error.js.map +1 -1
  39. package/lib/index.js +5 -2
  40. package/lib/index.js.map +1 -1
  41. package/lib/mongo_client.js +46 -26
  42. package/lib/mongo_client.js.map +1 -1
  43. package/lib/mongo_logger.js +102 -3
  44. package/lib/mongo_logger.js.map +1 -1
  45. package/lib/operations/execute_operation.js +9 -5
  46. package/lib/operations/execute_operation.js.map +1 -1
  47. package/lib/operations/list_collections.js.map +1 -1
  48. package/lib/operations/operation.js +4 -5
  49. package/lib/operations/operation.js.map +1 -1
  50. package/lib/sdam/monitor.js +25 -31
  51. package/lib/sdam/monitor.js.map +1 -1
  52. package/lib/sdam/server.js +27 -17
  53. package/lib/sdam/server.js.map +1 -1
  54. package/lib/sdam/topology.js +20 -19
  55. package/lib/sdam/topology.js.map +1 -1
  56. package/lib/sessions.js +24 -48
  57. package/lib/sessions.js.map +1 -1
  58. package/lib/utils.js +64 -44
  59. package/lib/utils.js.map +1 -1
  60. package/mongodb.d.ts +176 -108
  61. package/package.json +1 -1
  62. package/src/bulk/common.ts +6 -9
  63. package/src/change_stream.ts +21 -33
  64. package/src/client-side-encryption/auto_encrypter.ts +12 -8
  65. package/src/client-side-encryption/client_encryption.ts +6 -4
  66. package/src/client-side-encryption/state_machine.ts +80 -36
  67. package/src/cmap/auth/mongodb_oidc.ts +1 -1
  68. package/src/cmap/command_monitoring_events.ts +10 -55
  69. package/src/cmap/connection.ts +37 -29
  70. package/src/cmap/connection_pool.ts +121 -145
  71. package/src/cmap/wire_protocol/on_data.ts +9 -2
  72. package/src/collection.ts +15 -8
  73. package/src/connection_string.ts +74 -99
  74. package/src/cursor/abstract_cursor.ts +71 -23
  75. package/src/cursor/aggregation_cursor.ts +5 -3
  76. package/src/cursor/find_cursor.ts +5 -3
  77. package/src/cursor/list_collections_cursor.ts +5 -3
  78. package/src/db.ts +11 -7
  79. package/src/encrypter.ts +6 -11
  80. package/src/error.ts +11 -23
  81. package/src/index.ts +3 -3
  82. package/src/mongo_client.ts +78 -47
  83. package/src/mongo_logger.ts +158 -11
  84. package/src/mongo_types.ts +38 -0
  85. package/src/operations/execute_operation.ts +11 -6
  86. package/src/operations/list_collections.ts +4 -1
  87. package/src/operations/operation.ts +8 -9
  88. package/src/sdam/monitor.ts +30 -38
  89. package/src/sdam/server.ts +33 -20
  90. package/src/sdam/topology.ts +29 -26
  91. package/src/sessions.ts +37 -58
  92. package/src/utils.ts +79 -43
package/src/db.ts CHANGED
@@ -8,7 +8,7 @@ import { ListCollectionsCursor } from './cursor/list_collections_cursor';
8
8
  import { RunCommandCursor, type RunCursorCommandOptions } from './cursor/run_command_cursor';
9
9
  import { MongoInvalidArgumentError } from './error';
10
10
  import type { MongoClient, PkFactory } from './mongo_client';
11
- import type { TODO_NODE_3286 } from './mongo_types';
11
+ import type { Abortable, TODO_NODE_3286 } from './mongo_types';
12
12
  import type { AggregateOptions } from './operations/aggregate';
13
13
  import { CollectionsOperation } from './operations/collections';
14
14
  import {
@@ -273,7 +273,7 @@ export class Db {
273
273
  * @param command - The command to run
274
274
  * @param options - Optional settings for the command
275
275
  */
276
- async command(command: Document, options?: RunCommandOptions): Promise<Document> {
276
+ async command(command: Document, options?: RunCommandOptions & Abortable): Promise<Document> {
277
277
  // Intentionally, we do not inherit options from parent for this operation.
278
278
  return await executeOperation(
279
279
  this.client,
@@ -284,7 +284,8 @@ export class Db {
284
284
  ...resolveBSONOptions(options),
285
285
  timeoutMS: options?.timeoutMS ?? this.timeoutMS,
286
286
  session: options?.session,
287
- readPreference: options?.readPreference
287
+ readPreference: options?.readPreference,
288
+ signal: options?.signal
288
289
  })
289
290
  )
290
291
  );
@@ -351,22 +352,25 @@ export class Db {
351
352
  */
352
353
  listCollections(
353
354
  filter: Document,
354
- options: Exclude<ListCollectionsOptions, 'nameOnly'> & { nameOnly: true }
355
+ options: Exclude<ListCollectionsOptions, 'nameOnly'> & { nameOnly: true } & Abortable
355
356
  ): ListCollectionsCursor<Pick<CollectionInfo, 'name' | 'type'>>;
356
357
  listCollections(
357
358
  filter: Document,
358
- options: Exclude<ListCollectionsOptions, 'nameOnly'> & { nameOnly: false }
359
+ options: Exclude<ListCollectionsOptions, 'nameOnly'> & { nameOnly: false } & Abortable
359
360
  ): ListCollectionsCursor<CollectionInfo>;
360
361
  listCollections<
361
362
  T extends Pick<CollectionInfo, 'name' | 'type'> | CollectionInfo =
362
363
  | Pick<CollectionInfo, 'name' | 'type'>
363
364
  | CollectionInfo
364
- >(filter?: Document, options?: ListCollectionsOptions): ListCollectionsCursor<T>;
365
+ >(filter?: Document, options?: ListCollectionsOptions & Abortable): ListCollectionsCursor<T>;
365
366
  listCollections<
366
367
  T extends Pick<CollectionInfo, 'name' | 'type'> | CollectionInfo =
367
368
  | Pick<CollectionInfo, 'name' | 'type'>
368
369
  | CollectionInfo
369
- >(filter: Document = {}, options: ListCollectionsOptions = {}): ListCollectionsCursor<T> {
370
+ >(
371
+ filter: Document = {},
372
+ options: ListCollectionsOptions & Abortable = {}
373
+ ): ListCollectionsCursor<T> {
370
374
  return new ListCollectionsCursor<T>(this, filter, resolveOptions(this, options));
371
375
  }
372
376
 
package/src/encrypter.ts CHANGED
@@ -7,9 +7,6 @@ import { MongoInvalidArgumentError, MongoMissingDependencyError } from './error'
7
7
  import { MongoClient, type MongoClientOptions } from './mongo_client';
8
8
  import { type Callback } from './utils';
9
9
 
10
- /** @internal */
11
- const kInternalClient = Symbol('internalClient');
12
-
13
10
  /** @internal */
14
11
  export interface EncrypterOptions {
15
12
  autoEncryption: AutoEncryptionOptions;
@@ -18,7 +15,7 @@ export interface EncrypterOptions {
18
15
 
19
16
  /** @internal */
20
17
  export class Encrypter {
21
- [kInternalClient]: MongoClient | null;
18
+ private internalClient: MongoClient | null;
22
19
  bypassAutoEncryption: boolean;
23
20
  needsConnecting: boolean;
24
21
  autoEncrypter: AutoEncrypter;
@@ -28,7 +25,7 @@ export class Encrypter {
28
25
  throw new MongoInvalidArgumentError('Option "autoEncryption" must be specified');
29
26
  }
30
27
  // initialize to null, if we call getInternalClient, we may set this it is important to not overwrite those function calls.
31
- this[kInternalClient] = null;
28
+ this.internalClient = null;
32
29
 
33
30
  this.bypassAutoEncryption = !!options.autoEncryption.bypassAutoEncryption;
34
31
  this.needsConnecting = false;
@@ -60,8 +57,7 @@ export class Encrypter {
60
57
  }
61
58
 
62
59
  getInternalClient(client: MongoClient, uri: string, options: MongoClientOptions): MongoClient {
63
- // TODO(NODE-4144): Remove new variable for type narrowing
64
- let internalClient = this[kInternalClient];
60
+ let internalClient = this.internalClient;
65
61
  if (internalClient == null) {
66
62
  const clonedOptions: MongoClientOptions = {};
67
63
 
@@ -77,7 +73,7 @@ export class Encrypter {
77
73
  clonedOptions.minPoolSize = 0;
78
74
 
79
75
  internalClient = new MongoClient(uri, clonedOptions);
80
- this[kInternalClient] = internalClient;
76
+ this.internalClient = internalClient;
81
77
 
82
78
  for (const eventName of MONGO_CLIENT_EVENTS) {
83
79
  for (const listener of client.listeners(eventName)) {
@@ -95,8 +91,7 @@ export class Encrypter {
95
91
  }
96
92
 
97
93
  async connectInternalClient(): Promise<void> {
98
- // TODO(NODE-4144): Remove new variable for type narrowing
99
- const internalClient = this[kInternalClient];
94
+ const internalClient = this.internalClient;
100
95
  if (this.needsConnecting && internalClient != null) {
101
96
  this.needsConnecting = false;
102
97
  await internalClient.connect();
@@ -114,7 +109,7 @@ export class Encrypter {
114
109
  } catch (autoEncrypterError) {
115
110
  error = autoEncrypterError;
116
111
  }
117
- const internalClient = this[kInternalClient];
112
+ const internalClient = this.internalClient;
118
113
  if (internalClient != null && client !== internalClient) {
119
114
  return await internalClient.close(force);
120
115
  }
package/src/error.ts CHANGED
@@ -10,9 +10,6 @@ import type { TopologyDescription } from './sdam/topology_description';
10
10
  /** @public */
11
11
  export type AnyError = MongoError | Error;
12
12
 
13
- /** @internal */
14
- const kErrorLabels = Symbol('errorLabels');
15
-
16
13
  /**
17
14
  * @internal
18
15
  * The legacy error message from the server that indicates the node is not a writable primary
@@ -129,7 +126,11 @@ function isAggregateError(e: unknown): e is Error & { errors: Error[] } {
129
126
  */
130
127
  export class MongoError extends Error {
131
128
  /** @internal */
132
- [kErrorLabels]: Set<string>;
129
+ private readonly errorLabelSet: Set<string> = new Set();
130
+ public get errorLabels(): string[] {
131
+ return Array.from(this.errorLabelSet);
132
+ }
133
+
133
134
  /**
134
135
  * This is a number in MongoServerError and a string in MongoDriverError
135
136
  * @privateRemarks
@@ -153,7 +154,6 @@ export class MongoError extends Error {
153
154
  **/
154
155
  constructor(message: string, options?: { cause?: Error }) {
155
156
  super(message, options);
156
- this[kErrorLabels] = new Set();
157
157
  }
158
158
 
159
159
  /** @internal */
@@ -188,15 +188,11 @@ export class MongoError extends Error {
188
188
  * @returns returns true if the error has the provided error label
189
189
  */
190
190
  hasErrorLabel(label: string): boolean {
191
- return this[kErrorLabels].has(label);
191
+ return this.errorLabelSet.has(label);
192
192
  }
193
193
 
194
194
  addErrorLabel(label: string): void {
195
- this[kErrorLabels].add(label);
196
- }
197
-
198
- get errorLabels(): string[] {
199
- return Array.from(this[kErrorLabels]);
195
+ this.errorLabelSet.add(label);
200
196
  }
201
197
  }
202
198
 
@@ -228,8 +224,9 @@ export class MongoServerError extends MongoError {
228
224
  **/
229
225
  constructor(message: ErrorDescription) {
230
226
  super(message.message || message.errmsg || message.$err || 'n/a');
227
+
231
228
  if (message.errorLabels) {
232
- this[kErrorLabels] = new Set(message.errorLabels);
229
+ for (const label of message.errorLabels) this.addErrorLabel(label);
233
230
  }
234
231
 
235
232
  this.errorResponse = message;
@@ -1028,12 +1025,6 @@ export class MongoTopologyClosedError extends MongoAPIError {
1028
1025
  }
1029
1026
  }
1030
1027
 
1031
- /** @internal */
1032
- const kBeforeHandshake = Symbol('beforeHandshake');
1033
- export function isNetworkErrorBeforeHandshake(err: MongoNetworkError): boolean {
1034
- return err[kBeforeHandshake] === true;
1035
- }
1036
-
1037
1028
  /** @public */
1038
1029
  export interface MongoNetworkErrorOptions {
1039
1030
  /** Indicates the timeout happened before a connection handshake completed */
@@ -1048,7 +1039,7 @@ export interface MongoNetworkErrorOptions {
1048
1039
  */
1049
1040
  export class MongoNetworkError extends MongoError {
1050
1041
  /** @internal */
1051
- [kBeforeHandshake]?: boolean;
1042
+ public readonly beforeHandshake: boolean;
1052
1043
 
1053
1044
  /**
1054
1045
  * **Do not use this constructor!**
@@ -1063,10 +1054,7 @@ export class MongoNetworkError extends MongoError {
1063
1054
  **/
1064
1055
  constructor(message: string, options?: MongoNetworkErrorOptions) {
1065
1056
  super(message, { cause: options?.cause });
1066
-
1067
- if (options && typeof options.beforeHandshake === 'boolean') {
1068
- this[kBeforeHandshake] = options.beforeHandshake;
1069
- }
1057
+ this.beforeHandshake = !!options?.beforeHandshake;
1070
1058
  }
1071
1059
 
1072
1060
  override get name(): string {
package/src/index.ts CHANGED
@@ -120,6 +120,7 @@ export { CURSOR_FLAGS, CursorTimeoutMode } from './cursor/abstract_cursor';
120
120
  export { MongoErrorLabel } from './error';
121
121
  export { ExplainVerbosity } from './explain';
122
122
  export { ServerApiVersion } from './mongo_client';
123
+ export { MongoLoggableComponent, SeverityLevel } from './mongo_logger';
123
124
  export { ReturnDocument } from './operations/find_and_modify';
124
125
  export { ProfilingLevel } from './operations/set_profiling_level';
125
126
  export { ReadConcernLevel } from './read_concern';
@@ -422,14 +423,13 @@ export type {
422
423
  LoggableServerHeartbeatStartedEvent,
423
424
  LoggableServerHeartbeatSucceededEvent,
424
425
  MongoDBLogWritable,
425
- MongoLoggableComponent,
426
426
  MongoLogger,
427
427
  MongoLoggerEnvOptions,
428
428
  MongoLoggerMongoClientOptions,
429
- MongoLoggerOptions,
430
- SeverityLevel
429
+ MongoLoggerOptions
431
430
  } from './mongo_logger';
432
431
  export type {
432
+ Abortable,
433
433
  CommonEvents,
434
434
  EventsDescription,
435
435
  GenericListener,
@@ -18,6 +18,7 @@ import type { ClientMetadata } from './cmap/handshake/client_metadata';
18
18
  import type { CompressorName } from './cmap/wire_protocol/compression';
19
19
  import { parseOptions, resolveSRVRecord } from './connection_string';
20
20
  import { MONGO_CLIENT_EVENTS } from './constants';
21
+ import { type AbstractCursor } from './cursor/abstract_cursor';
21
22
  import { Db, type DbOptions } from './db';
22
23
  import type { Encrypter } from './encrypter';
23
24
  import { MongoInvalidArgumentError } from './error';
@@ -277,29 +278,29 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC
277
278
  proxyPassword?: string;
278
279
  /** Instructs the driver monitors to use a specific monitoring mode */
279
280
  serverMonitoringMode?: ServerMonitoringMode;
280
-
281
- /** @internal */
282
- srvPoller?: SrvPoller;
283
- /** @internal */
284
- connectionType?: typeof Connection;
285
281
  /**
286
- * @internal
287
- * TODO: NODE-5671 - remove internal flag
282
+ * @public
283
+ * Specifies the destination of the driver's logging. The default is stderr.
288
284
  */
289
285
  mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable;
290
286
  /**
291
- * @internal
292
- * TODO: NODE-5671 - remove internal flag
287
+ * @public
288
+ * Enable logging level per component or use `default` to control any unset components.
293
289
  */
294
290
  mongodbLogComponentSeverities?: LogComponentSeveritiesClientOptions;
295
291
  /**
296
- * @internal
297
- * TODO: NODE-5671 - remove internal flag
292
+ * @public
293
+ * All BSON documents are stringified to EJSON. This controls the maximum length of those strings.
294
+ * It is defaulted to 1000.
298
295
  */
299
296
  mongodbLogMaxDocumentLength?: number;
300
297
 
301
298
  /** @internal */
302
- [featureFlag: symbol]: any;
299
+ srvPoller?: SrvPoller;
300
+ /** @internal */
301
+ connectionType?: typeof Connection;
302
+ /** @internal */
303
+ __skipPingOnConnect?: boolean;
303
304
  }
304
305
 
305
306
  /** @public */
@@ -318,6 +319,12 @@ export interface MongoClientPrivate {
318
319
  * - used to notify the leak checker in our tests if test author forgot to clean up explicit sessions
319
320
  */
320
321
  readonly activeSessions: Set<ClientSession>;
322
+ /**
323
+ * We keep a reference to the cursors that are created from this client.
324
+ * - used to track and close all cursors in client.close().
325
+ * Cursors in this set are ones that still need to have their close method invoked (no other conditions are considered)
326
+ */
327
+ readonly activeCursors: Set<AbstractCursor>;
321
328
  readonly sessionPool: ServerSessionPool;
322
329
  readonly options: MongoOptions;
323
330
  readonly readConcern?: ReadConcern;
@@ -333,9 +340,6 @@ export type MongoClientEvents = Pick<TopologyEvents, (typeof MONGO_CLIENT_EVENTS
333
340
  open(mongoClient: MongoClient): void;
334
341
  };
335
342
 
336
- /** @internal */
337
- const kOptions = Symbol('options');
338
-
339
343
  /**
340
344
  * The **MongoClient** class is a class that allows for making Connections to MongoDB.
341
345
  * @public
@@ -364,23 +368,27 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
364
368
  override readonly mongoLogger: MongoLogger | undefined;
365
369
  /** @internal */
366
370
  private connectionLock?: Promise<this>;
371
+ /** @internal */
372
+ private closeLock?: Promise<void>;
367
373
 
368
374
  /**
369
375
  * The consolidate, parsed, transformed and merged options.
370
- * @internal
371
376
  */
372
- [kOptions]: MongoOptions;
377
+ public readonly options: Readonly<
378
+ Omit<MongoOptions, 'monitorCommands' | 'ca' | 'crl' | 'key' | 'cert'>
379
+ > &
380
+ Pick<MongoOptions, 'monitorCommands' | 'ca' | 'crl' | 'key' | 'cert'>;
373
381
 
374
382
  constructor(url: string, options?: MongoClientOptions) {
375
383
  super();
376
384
 
377
- this[kOptions] = parseOptions(url, this, options);
385
+ this.options = parseOptions(url, this, options);
378
386
 
379
- const shouldSetLogger = Object.values(
380
- this[kOptions].mongoLoggerOptions.componentSeverities
381
- ).some(value => value !== SeverityLevel.OFF);
387
+ const shouldSetLogger = Object.values(this.options.mongoLoggerOptions.componentSeverities).some(
388
+ value => value !== SeverityLevel.OFF
389
+ );
382
390
  this.mongoLogger = shouldSetLogger
383
- ? new MongoLogger(this[kOptions].mongoLoggerOptions)
391
+ ? new MongoLogger(this.options.mongoLoggerOptions)
384
392
  : undefined;
385
393
 
386
394
  // eslint-disable-next-line @typescript-eslint/no-this-alias
@@ -389,24 +397,25 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
389
397
  // The internal state
390
398
  this.s = {
391
399
  url,
392
- bsonOptions: resolveBSONOptions(this[kOptions]),
400
+ bsonOptions: resolveBSONOptions(this.options),
393
401
  namespace: ns('admin'),
394
402
  hasBeenClosed: false,
395
403
  sessionPool: new ServerSessionPool(this),
396
404
  activeSessions: new Set(),
405
+ activeCursors: new Set(),
397
406
  authProviders: new MongoClientAuthProviders(),
398
407
 
399
408
  get options() {
400
- return client[kOptions];
409
+ return client.options;
401
410
  },
402
411
  get readConcern() {
403
- return client[kOptions].readConcern;
412
+ return client.options.readConcern;
404
413
  },
405
414
  get writeConcern() {
406
- return client[kOptions].writeConcern;
415
+ return client.options.writeConcern;
407
416
  },
408
417
  get readPreference() {
409
- return client[kOptions].readPreference;
418
+ return client.options.readPreference;
410
419
  },
411
420
  get isMongoClient(): true {
412
421
  return true;
@@ -428,15 +437,15 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
428
437
 
429
438
  /** @internal */
430
439
  private checkForNonGenuineHosts() {
431
- const documentDBHostnames = this[kOptions].hosts.filter((hostAddress: HostAddress) =>
440
+ const documentDBHostnames = this.options.hosts.filter((hostAddress: HostAddress) =>
432
441
  isHostMatch(DOCUMENT_DB_CHECK, hostAddress.host)
433
442
  );
434
- const srvHostIsDocumentDB = isHostMatch(DOCUMENT_DB_CHECK, this[kOptions].srvHost);
443
+ const srvHostIsDocumentDB = isHostMatch(DOCUMENT_DB_CHECK, this.options.srvHost);
435
444
 
436
- const cosmosDBHostnames = this[kOptions].hosts.filter((hostAddress: HostAddress) =>
445
+ const cosmosDBHostnames = this.options.hosts.filter((hostAddress: HostAddress) =>
437
446
  isHostMatch(COSMOS_DB_CHECK, hostAddress.host)
438
447
  );
439
- const srvHostIsCosmosDB = isHostMatch(COSMOS_DB_CHECK, this[kOptions].srvHost);
448
+ const srvHostIsCosmosDB = isHostMatch(COSMOS_DB_CHECK, this.options.srvHost);
440
449
 
441
450
  if (documentDBHostnames.length !== 0 || srvHostIsDocumentDB) {
442
451
  this.mongoLogger?.info('client', DOCUMENT_DB_MSG);
@@ -445,28 +454,23 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
445
454
  }
446
455
  }
447
456
 
448
- /** @see MongoOptions */
449
- get options(): Readonly<MongoOptions> {
450
- return Object.freeze({ ...this[kOptions] });
451
- }
452
-
453
457
  get serverApi(): Readonly<ServerApi | undefined> {
454
- return this[kOptions].serverApi && Object.freeze({ ...this[kOptions].serverApi });
458
+ return this.options.serverApi && Object.freeze({ ...this.options.serverApi });
455
459
  }
456
460
  /**
457
461
  * Intended for APM use only
458
462
  * @internal
459
463
  */
460
464
  get monitorCommands(): boolean {
461
- return this[kOptions].monitorCommands;
465
+ return this.options.monitorCommands;
462
466
  }
463
467
  set monitorCommands(value: boolean) {
464
- this[kOptions].monitorCommands = value;
468
+ this.options.monitorCommands = value;
465
469
  }
466
470
 
467
471
  /** @internal */
468
472
  get autoEncrypter(): AutoEncrypter | undefined {
469
- return this[kOptions].autoEncrypter;
473
+ return this.options.autoEncrypter;
470
474
  }
471
475
 
472
476
  get readConcern(): ReadConcern | undefined {
@@ -522,6 +526,10 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
522
526
  * This means the time to setup the `MongoClient` does not count against `timeoutMS`.
523
527
  * If you are using `timeoutMS` we recommend connecting your client explicitly in advance of any operation to avoid this inconsistent execution time.
524
528
  *
529
+ * @remarks
530
+ * The driver will look up corresponding SRV and TXT records if the connection string starts with `mongodb+srv://`.
531
+ * If those look ups throw a DNS Timeout error, the driver will retry the look up once.
532
+ *
525
533
  * @see docs.mongodb.org/manual/reference/connection-string/
526
534
  */
527
535
  async connect(): Promise<this> {
@@ -551,7 +559,7 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
551
559
  return this;
552
560
  }
553
561
 
554
- const options = this[kOptions];
562
+ const options = this.options;
555
563
 
556
564
  if (options.tls) {
557
565
  if (typeof options.tlsCAFile === 'string') {
@@ -639,6 +647,21 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
639
647
  * @param force - Force close, emitting no events
640
648
  */
641
649
  async close(force = false): Promise<void> {
650
+ if (this.closeLock) {
651
+ return await this.closeLock;
652
+ }
653
+
654
+ try {
655
+ this.closeLock = this._close(force);
656
+ await this.closeLock;
657
+ } finally {
658
+ // release
659
+ this.closeLock = undefined;
660
+ }
661
+ }
662
+
663
+ /* @internal */
664
+ private async _close(force = false): Promise<void> {
642
665
  // There's no way to set hasBeenClosed back to false
643
666
  Object.defineProperty(this.s, 'hasBeenClosed', {
644
667
  value: true,
@@ -647,6 +670,11 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
647
670
  writable: false
648
671
  });
649
672
 
673
+ const activeCursorCloses = Array.from(this.s.activeCursors, cursor => cursor.close());
674
+ this.s.activeCursors.clear();
675
+
676
+ await Promise.all(activeCursorCloses);
677
+
650
678
  const activeSessionEnds = Array.from(this.s.activeSessions, session => session.endSession());
651
679
  this.s.activeSessions.clear();
652
680
 
@@ -685,7 +713,7 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
685
713
 
686
714
  topology.close();
687
715
 
688
- const { encrypter } = this[kOptions];
716
+ const { encrypter } = this.options;
689
717
  if (encrypter) {
690
718
  await encrypter.close(this, force);
691
719
  }
@@ -706,7 +734,7 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
706
734
  }
707
735
 
708
736
  // Copy the options and add out internal override of the not shared flag
709
- const finalOptions = Object.assign({}, this[kOptions], options);
737
+ const finalOptions = Object.assign({}, this.options, options);
710
738
 
711
739
  // Return the db object
712
740
  const db = new Db(this, dbName, finalOptions);
@@ -728,6 +756,10 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
728
756
  * @remarks
729
757
  * The programmatically provided options take precedence over the URI options.
730
758
  *
759
+ * @remarks
760
+ * The driver will look up corresponding SRV and TXT records if the connection string starts with `mongodb+srv://`.
761
+ * If those look ups throw a DNS Timeout error, the driver will retry the look up once.
762
+ *
731
763
  * @see https://www.mongodb.com/docs/manual/reference/connection-string/
732
764
  */
733
765
  static async connect(url: string, options?: MongoClientOptions): Promise<MongoClient> {
@@ -748,7 +780,7 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
748
780
  this,
749
781
  this.s.sessionPool,
750
782
  { explicit: true, ...options },
751
- this[kOptions]
783
+ this.options
752
784
  );
753
785
  this.s.activeSessions.add(session);
754
786
  session.once('ended', () => {
@@ -1012,9 +1044,6 @@ export interface MongoOptions
1012
1044
  tlsCRLFile?: string;
1013
1045
  tlsCertificateKeyFile?: string;
1014
1046
 
1015
- /** @internal */
1016
- [featureFlag: symbol]: any;
1017
-
1018
1047
  /**
1019
1048
  * @internal
1020
1049
  * TODO: NODE-5671 - remove internal flag
@@ -1026,4 +1055,6 @@ export interface MongoOptions
1026
1055
  */
1027
1056
  mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable;
1028
1057
  timeoutMS?: number;
1058
+ /** @internal */
1059
+ __skipPingOnConnect?: boolean;
1029
1060
  }