mongodb 5.4.0 → 5.6.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 (81) hide show
  1. package/lib/admin.js +5 -5
  2. package/lib/admin.js.map +1 -1
  3. package/lib/bulk/common.js +4 -4
  4. package/lib/bulk/common.js.map +1 -1
  5. package/lib/change_stream.js +2 -2
  6. package/lib/change_stream.js.map +1 -1
  7. package/lib/cmap/connection_pool.js +21 -17
  8. package/lib/cmap/connection_pool.js.map +1 -1
  9. package/lib/cmap/handshake/client_metadata.js +1 -1
  10. package/lib/cmap/handshake/client_metadata.js.map +1 -1
  11. package/lib/cmap/wire_protocol/constants.js +3 -1
  12. package/lib/cmap/wire_protocol/constants.js.map +1 -1
  13. package/lib/collection.js +108 -33
  14. package/lib/collection.js.map +1 -1
  15. package/lib/cursor/list_collections_cursor.js +2 -2
  16. package/lib/cursor/list_collections_cursor.js.map +1 -1
  17. package/lib/cursor/list_indexes_cursor.js +2 -2
  18. package/lib/cursor/list_indexes_cursor.js.map +1 -1
  19. package/lib/cursor/list_search_indexes_cursor.js +14 -0
  20. package/lib/cursor/list_search_indexes_cursor.js.map +1 -0
  21. package/lib/cursor/run_command_cursor.js +94 -0
  22. package/lib/cursor/run_command_cursor.js.map +1 -0
  23. package/lib/db.js +29 -17
  24. package/lib/db.js.map +1 -1
  25. package/lib/error.js +16 -4
  26. package/lib/error.js.map +1 -1
  27. package/lib/index.js.map +1 -1
  28. package/lib/mongo_client.js +5 -7
  29. package/lib/mongo_client.js.map +1 -1
  30. package/lib/mongo_types.js +6 -1
  31. package/lib/mongo_types.js.map +1 -1
  32. package/lib/operations/create_collection.js +10 -3
  33. package/lib/operations/create_collection.js.map +1 -1
  34. package/lib/operations/drop.js +2 -3
  35. package/lib/operations/drop.js.map +1 -1
  36. package/lib/operations/search_indexes/create.js +29 -0
  37. package/lib/operations/search_indexes/create.js.map +1 -0
  38. package/lib/operations/search_indexes/drop.js +30 -0
  39. package/lib/operations/search_indexes/drop.js.map +1 -0
  40. package/lib/operations/search_indexes/update.js +30 -0
  41. package/lib/operations/search_indexes/update.js.map +1 -0
  42. package/lib/sdam/monitor.js +1 -1
  43. package/lib/sdam/monitor.js.map +1 -1
  44. package/lib/sdam/server.js +31 -19
  45. package/lib/sdam/server.js.map +1 -1
  46. package/lib/sdam/topology.js +4 -3
  47. package/lib/sdam/topology.js.map +1 -1
  48. package/lib/sessions.js +2 -2
  49. package/lib/sessions.js.map +1 -1
  50. package/lib/utils.js +19 -7
  51. package/lib/utils.js.map +1 -1
  52. package/mongodb.d.ts +112 -16
  53. package/package.json +17 -17
  54. package/src/admin.ts +5 -5
  55. package/src/bulk/common.ts +4 -4
  56. package/src/change_stream.ts +2 -2
  57. package/src/cmap/connection_pool.ts +26 -18
  58. package/src/cmap/handshake/client_metadata.ts +2 -1
  59. package/src/cmap/wire_protocol/constants.ts +2 -0
  60. package/src/collection.ts +163 -41
  61. package/src/cursor/abstract_cursor.ts +1 -1
  62. package/src/cursor/list_collections_cursor.ts +2 -2
  63. package/src/cursor/list_indexes_cursor.ts +2 -2
  64. package/src/cursor/list_search_indexes_cursor.ts +20 -0
  65. package/src/cursor/run_command_cursor.ts +140 -0
  66. package/src/db.ts +34 -21
  67. package/src/deps.ts +2 -2
  68. package/src/error.ts +20 -3
  69. package/src/index.ts +9 -0
  70. package/src/mongo_client.ts +25 -17
  71. package/src/mongo_types.ts +16 -2
  72. package/src/operations/create_collection.ts +19 -5
  73. package/src/operations/drop.ts +2 -3
  74. package/src/operations/search_indexes/create.ts +48 -0
  75. package/src/operations/search_indexes/drop.ts +35 -0
  76. package/src/operations/search_indexes/update.ts +36 -0
  77. package/src/sdam/monitor.ts +1 -1
  78. package/src/sdam/server.ts +38 -23
  79. package/src/sdam/topology.ts +8 -3
  80. package/src/sessions.ts +2 -2
  81. package/src/utils.ts +18 -10
@@ -0,0 +1,20 @@
1
+ import type { Collection } from '../collection';
2
+ import type { AggregateOptions } from '../operations/aggregate';
3
+ import { AggregationCursor } from './aggregation_cursor';
4
+
5
+ /** @internal */
6
+ export type ListSearchIndexesOptions = AggregateOptions;
7
+
8
+ /** @internal */
9
+ export class ListSearchIndexesCursor extends AggregationCursor<{ name: string }> {
10
+ /** @internal */
11
+ constructor(
12
+ { fullNamespace: ns, client }: Collection,
13
+ name: string | null,
14
+ options: ListSearchIndexesOptions = {}
15
+ ) {
16
+ const pipeline =
17
+ name == null ? [{ $listSearchIndexes: {} }] : [{ $listSearchIndexes: { name } }];
18
+ super(client, ns, pipeline, options);
19
+ }
20
+ }
@@ -0,0 +1,140 @@
1
+ import type { BSONSerializeOptions, Document, Long } from '../bson';
2
+ import type { Db } from '../db';
3
+ import { MongoAPIError, MongoUnexpectedServerResponseError } from '../error';
4
+ import { executeOperation, ExecutionResult } from '../operations/execute_operation';
5
+ import { GetMoreOperation } from '../operations/get_more';
6
+ import { RunCommandOperation } from '../operations/run_command';
7
+ import type { ReadConcernLike } from '../read_concern';
8
+ import type { ReadPreferenceLike } from '../read_preference';
9
+ import type { ClientSession } from '../sessions';
10
+ import { Callback, ns } from '../utils';
11
+ import { AbstractCursor } from './abstract_cursor';
12
+
13
+ /** @public */
14
+ export type RunCursorCommandOptions = {
15
+ readPreference?: ReadPreferenceLike;
16
+ session?: ClientSession;
17
+ } & BSONSerializeOptions;
18
+
19
+ /** @internal */
20
+ type RunCursorCommandResponse = {
21
+ cursor: { id: bigint | Long | number; ns: string; firstBatch: Document[] };
22
+ ok: 1;
23
+ };
24
+
25
+ /** @public */
26
+ export class RunCommandCursor extends AbstractCursor {
27
+ public readonly command: Readonly<Record<string, any>>;
28
+ public readonly getMoreOptions: {
29
+ comment?: any;
30
+ maxAwaitTimeMS?: number;
31
+ batchSize?: number;
32
+ } = {};
33
+
34
+ /**
35
+ * Controls the `getMore.comment` field
36
+ * @param comment - any BSON value
37
+ */
38
+ public setComment(comment: any): this {
39
+ this.getMoreOptions.comment = comment;
40
+ return this;
41
+ }
42
+
43
+ /**
44
+ * Controls the `getMore.maxTimeMS` field. Only valid when cursor is tailable await
45
+ * @param maxTimeMS - the number of milliseconds to wait for new data
46
+ */
47
+ public setMaxTimeMS(maxTimeMS: number): this {
48
+ this.getMoreOptions.maxAwaitTimeMS = maxTimeMS;
49
+ return this;
50
+ }
51
+
52
+ /**
53
+ * Controls the `getMore.batchSize` field
54
+ * @param maxTimeMS - the number documents to return in the `nextBatch`
55
+ */
56
+ public setBatchSize(batchSize: number): this {
57
+ this.getMoreOptions.batchSize = batchSize;
58
+ return this;
59
+ }
60
+
61
+ /** Unsupported for RunCommandCursor */
62
+ public override clone(): never {
63
+ throw new MongoAPIError('Clone not supported, create a new cursor with db.runCursorCommand');
64
+ }
65
+
66
+ /** Unsupported for RunCommandCursor: readConcern must be configured directly on command document */
67
+ public override withReadConcern(_: ReadConcernLike): never {
68
+ throw new MongoAPIError(
69
+ 'RunCommandCursor does not support readConcern it must be attached to the command being run'
70
+ );
71
+ }
72
+
73
+ /** Unsupported for RunCommandCursor: various cursor flags must be configured directly on command document */
74
+ public override addCursorFlag(_: string, __: boolean): never {
75
+ throw new MongoAPIError(
76
+ 'RunCommandCursor does not support cursor flags, they must be attached to the command being run'
77
+ );
78
+ }
79
+
80
+ /** Unsupported for RunCommandCursor: maxTimeMS must be configured directly on command document */
81
+ public override maxTimeMS(_: number): never {
82
+ throw new MongoAPIError(
83
+ 'maxTimeMS must be configured on the command document directly, to configure getMore.maxTimeMS use cursor.setMaxTimeMS()'
84
+ );
85
+ }
86
+
87
+ /** Unsupported for RunCommandCursor: batchSize must be configured directly on command document */
88
+ public override batchSize(_: number): never {
89
+ throw new MongoAPIError(
90
+ 'batchSize must be configured on the command document directly, to configure getMore.batchSize use cursor.setBatchSize()'
91
+ );
92
+ }
93
+
94
+ /** @internal */
95
+ private db: Db;
96
+
97
+ /** @internal */
98
+ constructor(db: Db, command: Document, options: RunCursorCommandOptions = {}) {
99
+ super(db.client, ns(db.namespace), options);
100
+ this.db = db;
101
+ this.command = Object.freeze({ ...command });
102
+ }
103
+
104
+ /** @internal */
105
+ protected _initialize(session: ClientSession, callback: Callback<ExecutionResult>) {
106
+ const operation = new RunCommandOperation<RunCursorCommandResponse>(this.db, this.command, {
107
+ ...this.cursorOptions,
108
+ session: session,
109
+ readPreference: this.cursorOptions.readPreference
110
+ });
111
+ executeOperation(this.client, operation).then(
112
+ response => {
113
+ if (response.cursor == null) {
114
+ callback(
115
+ new MongoUnexpectedServerResponseError('Expected server to respond with cursor')
116
+ );
117
+ return;
118
+ }
119
+ callback(undefined, {
120
+ server: operation.server,
121
+ session,
122
+ response
123
+ });
124
+ },
125
+ err => callback(err)
126
+ );
127
+ }
128
+
129
+ /** @internal */
130
+ override _getMore(_batchSize: number, callback: Callback<Document>) {
131
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
132
+ const getMoreOperation = new GetMoreOperation(this.namespace, this.id!, this.server!, {
133
+ ...this.cursorOptions,
134
+ session: this.session,
135
+ ...this.getMoreOptions
136
+ });
137
+
138
+ executeOperation(this.client, getMoreOperation, callback);
139
+ }
140
+ }
package/src/db.ts CHANGED
@@ -5,6 +5,7 @@ import { Collection, CollectionOptions } from './collection';
5
5
  import * as CONSTANTS from './constants';
6
6
  import { AggregationCursor } from './cursor/aggregation_cursor';
7
7
  import { ListCollectionsCursor } from './cursor/list_collections_cursor';
8
+ import { RunCommandCursor, type RunCursorCommandOptions } from './cursor/run_command_cursor';
8
9
  import { MongoAPIError, MongoInvalidArgumentError } from './error';
9
10
  import type { MongoClient, PkFactory } from './mongo_client';
10
11
  import type { TODO_NODE_3286 } from './mongo_types';
@@ -69,7 +70,6 @@ const DB_OPTIONS_ALLOW_LIST = [
69
70
 
70
71
  /** @internal */
71
72
  export interface DbPrivate {
72
- client: MongoClient;
73
73
  options?: DbOptions;
74
74
  readPreference?: ReadPreference;
75
75
  pkFactory: PkFactory;
@@ -121,6 +121,9 @@ export class Db {
121
121
  /** @internal */
122
122
  s: DbPrivate;
123
123
 
124
+ /** @internal */
125
+ readonly client: MongoClient;
126
+
124
127
  public static SYSTEM_NAMESPACE_COLLECTION = CONSTANTS.SYSTEM_NAMESPACE_COLLECTION;
125
128
  public static SYSTEM_INDEX_COLLECTION = CONSTANTS.SYSTEM_INDEX_COLLECTION;
126
129
  public static SYSTEM_PROFILE_COLLECTION = CONSTANTS.SYSTEM_PROFILE_COLLECTION;
@@ -146,8 +149,6 @@ export class Db {
146
149
 
147
150
  // Internal state of the db object
148
151
  this.s = {
149
- // Client
150
- client,
151
152
  // Options
152
153
  options,
153
154
  // Unpack read preference
@@ -162,6 +163,8 @@ export class Db {
162
163
  // Namespace
163
164
  namespace: new MongoDBNamespace(databaseName)
164
165
  };
166
+
167
+ this.client = client;
165
168
  }
166
169
 
167
170
  get databaseName(): string {
@@ -190,7 +193,7 @@ export class Db {
190
193
  */
191
194
  get readPreference(): ReadPreference {
192
195
  if (this.s.readPreference == null) {
193
- return this.s.client.readPreference;
196
+ return this.client.readPreference;
194
197
  }
195
198
 
196
199
  return this.s.readPreference;
@@ -221,7 +224,7 @@ export class Db {
221
224
  options?: CreateCollectionOptions
222
225
  ): Promise<Collection<TSchema>> {
223
226
  return executeOperation(
224
- this.s.client,
227
+ this.client,
225
228
  new CreateCollectionOperation(this, name, resolveOptions(this, options)) as TODO_NODE_3286
226
229
  );
227
230
  }
@@ -253,7 +256,7 @@ export class Db {
253
256
  */
254
257
  async command(command: Document, options?: RunCommandOptions): Promise<Document> {
255
258
  // Intentionally, we do not inherit options from parent for this operation.
256
- return executeOperation(this.s.client, new RunCommandOperation(this, command, options));
259
+ return executeOperation(this.client, new RunCommandOperation(this, command, options));
257
260
  }
258
261
 
259
262
  /**
@@ -267,7 +270,7 @@ export class Db {
267
270
  options?: AggregateOptions
268
271
  ): AggregationCursor<T> {
269
272
  return new AggregationCursor(
270
- this.s.client,
273
+ this.client,
271
274
  this.s.namespace,
272
275
  pipeline,
273
276
  resolveOptions(this, options)
@@ -301,10 +304,7 @@ export class Db {
301
304
  * @param options - Optional settings for the command
302
305
  */
303
306
  async stats(options?: DbStatsOptions): Promise<Document> {
304
- return executeOperation(
305
- this.s.client,
306
- new DbStatsOperation(this, resolveOptions(this, options))
307
- );
307
+ return executeOperation(this.client, new DbStatsOperation(this, resolveOptions(this, options)));
308
308
  }
309
309
 
310
310
  /**
@@ -351,7 +351,7 @@ export class Db {
351
351
  ): Promise<Collection<TSchema>> {
352
352
  // Intentionally, we do not inherit options from parent for this operation.
353
353
  return executeOperation(
354
- this.s.client,
354
+ this.client,
355
355
  new RenameOperation(
356
356
  this.collection<TSchema>(fromCollection) as TODO_NODE_3286,
357
357
  toCollection,
@@ -368,7 +368,7 @@ export class Db {
368
368
  */
369
369
  async dropCollection(name: string, options?: DropCollectionOptions): Promise<boolean> {
370
370
  return executeOperation(
371
- this.s.client,
371
+ this.client,
372
372
  new DropCollectionOperation(this, name, resolveOptions(this, options))
373
373
  );
374
374
  }
@@ -380,7 +380,7 @@ export class Db {
380
380
  */
381
381
  async dropDatabase(options?: DropDatabaseOptions): Promise<boolean> {
382
382
  return executeOperation(
383
- this.s.client,
383
+ this.client,
384
384
  new DropDatabaseOperation(this, resolveOptions(this, options))
385
385
  );
386
386
  }
@@ -392,7 +392,7 @@ export class Db {
392
392
  */
393
393
  async collections(options?: ListCollectionsOptions): Promise<Collection[]> {
394
394
  return executeOperation(
395
- this.s.client,
395
+ this.client,
396
396
  new CollectionsOperation(this, resolveOptions(this, options))
397
397
  );
398
398
  }
@@ -410,7 +410,7 @@ export class Db {
410
410
  options?: CreateIndexesOptions
411
411
  ): Promise<string> {
412
412
  return executeOperation(
413
- this.s.client,
413
+ this.client,
414
414
  new CreateIndexOperation(this, name, indexSpec, resolveOptions(this, options))
415
415
  );
416
416
  }
@@ -437,7 +437,7 @@ export class Db {
437
437
  : undefined;
438
438
  const password = typeof passwordOrOptions === 'string' ? passwordOrOptions : undefined;
439
439
  return executeOperation(
440
- this.s.client,
440
+ this.client,
441
441
  new AddUserOperation(this, username, password, resolveOptions(this, options))
442
442
  );
443
443
  }
@@ -450,7 +450,7 @@ export class Db {
450
450
  */
451
451
  async removeUser(username: string, options?: RemoveUserOptions): Promise<boolean> {
452
452
  return executeOperation(
453
- this.s.client,
453
+ this.client,
454
454
  new RemoveUserOperation(this, username, resolveOptions(this, options))
455
455
  );
456
456
  }
@@ -466,7 +466,7 @@ export class Db {
466
466
  options?: SetProfilingLevelOptions
467
467
  ): Promise<ProfilingLevel> {
468
468
  return executeOperation(
469
- this.s.client,
469
+ this.client,
470
470
  new SetProfilingLevelOperation(this, level, resolveOptions(this, options))
471
471
  );
472
472
  }
@@ -478,7 +478,7 @@ export class Db {
478
478
  */
479
479
  async profilingLevel(options?: ProfilingLevelOptions): Promise<string> {
480
480
  return executeOperation(
481
- this.s.client,
481
+ this.client,
482
482
  new ProfilingLevelOperation(this, resolveOptions(this, options))
483
483
  );
484
484
  }
@@ -491,7 +491,7 @@ export class Db {
491
491
  */
492
492
  async indexInformation(name: string, options?: IndexInformationOptions): Promise<Document> {
493
493
  return executeOperation(
494
- this.s.client,
494
+ this.client,
495
495
  new IndexInformationOperation(this, name, resolveOptions(this, options))
496
496
  );
497
497
  }
@@ -523,6 +523,19 @@ export class Db {
523
523
 
524
524
  return new ChangeStream<TSchema, TChange>(this, pipeline, resolveOptions(this, options));
525
525
  }
526
+
527
+ /**
528
+ * A low level cursor API providing basic driver functionality:
529
+ * - ClientSession management
530
+ * - ReadPreference for server selection
531
+ * - Running getMores automatically when a local batch is exhausted
532
+ *
533
+ * @param command - The command that will start a cursor on the server.
534
+ * @param options - Configurations for running the command, bson options will apply to getMores
535
+ */
536
+ runCursorCommand(command: Document, options?: RunCursorCommandOptions): RunCommandCursor {
537
+ return new RunCommandCursor(this, command, options);
538
+ }
526
539
  }
527
540
 
528
541
  // TODO(NODE-3484): Refactor into MongoDBNamespace
package/src/deps.ts CHANGED
@@ -309,11 +309,11 @@ export interface AutoEncryptionOptions {
309
309
  * Other validation rules in the JSON schema will not be enforced by the driver and will result in an error.
310
310
  */
311
311
  schemaMap?: Document;
312
- /** @experimental Public Technical Preview: Supply a schema for the encrypted fields in the document */
312
+ /** Supply a schema for the encrypted fields in the document */
313
313
  encryptedFieldsMap?: Document;
314
314
  /** Allows the user to bypass auto encryption, maintaining implicit decryption */
315
315
  bypassAutoEncryption?: boolean;
316
- /** @experimental Public Technical Preview: Allows users to bypass query analysis */
316
+ /** Allows users to bypass query analysis */
317
317
  bypassQueryAnalysis?: boolean;
318
318
  options?: {
319
319
  /** An optional hook to catch logging messages from the underlying encryption engine */
package/src/error.ts CHANGED
@@ -108,6 +108,10 @@ export interface ErrorDescription extends Document {
108
108
  errInfo?: Document;
109
109
  }
110
110
 
111
+ function isAggregateError(e: Error): e is Error & { errors: Error[] } {
112
+ return 'errors' in e && Array.isArray(e.errors);
113
+ }
114
+
111
115
  /**
112
116
  * @public
113
117
  * @category Error
@@ -131,15 +135,28 @@ export class MongoError extends Error {
131
135
  cause?: Error; // depending on the node version, this may or may not exist on the base
132
136
 
133
137
  constructor(message: string | Error) {
138
+ super(MongoError.buildErrorMessage(message));
134
139
  if (message instanceof Error) {
135
- super(message.message);
136
140
  this.cause = message;
137
- } else {
138
- super(message);
139
141
  }
142
+
140
143
  this[kErrorLabels] = new Set();
141
144
  }
142
145
 
146
+ /** @internal */
147
+ private static buildErrorMessage(e: Error | string): string {
148
+ if (typeof e === 'string') {
149
+ return e;
150
+ }
151
+ if (isAggregateError(e) && e.message.length === 0) {
152
+ return e.errors.length === 0
153
+ ? 'AggregateError has an empty errors array. Please check the `cause` property for more information.'
154
+ : e.errors.map(({ message }) => message).join(', ');
155
+ }
156
+
157
+ return e.message;
158
+ }
159
+
143
160
  override get name(): string {
144
161
  return 'MongoError';
145
162
  }
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ import { AggregationCursor } from './cursor/aggregation_cursor';
8
8
  import { FindCursor } from './cursor/find_cursor';
9
9
  import { ListCollectionsCursor } from './cursor/list_collections_cursor';
10
10
  import { ListIndexesCursor } from './cursor/list_indexes_cursor';
11
+ import type { RunCommandCursor } from './cursor/run_command_cursor';
11
12
  import { Db } from './db';
12
13
  import { GridFSBucket } from './gridfs';
13
14
  import { GridFSBucketReadStream } from './gridfs/download';
@@ -87,6 +88,7 @@ export {
87
88
  ListIndexesCursor,
88
89
  MongoClient,
89
90
  OrderedBulkOperation,
91
+ RunCommandCursor,
90
92
  UnorderedBulkOperation
91
93
  };
92
94
 
@@ -275,6 +277,11 @@ export type {
275
277
  ChangeStreamAggregateRawResult,
276
278
  ChangeStreamCursorOptions
277
279
  } from './cursor/change_stream_cursor';
280
+ export type {
281
+ ListSearchIndexesCursor,
282
+ ListSearchIndexesOptions
283
+ } from './cursor/list_search_indexes_cursor';
284
+ export type { RunCursorCommandOptions } from './cursor/run_command_cursor';
278
285
  export type { DbOptions, DbPrivate } from './db';
279
286
  export type { AutoEncrypter, AutoEncryptionOptions, AutoEncryptionTlsOptions } from './deps';
280
287
  export type { Encrypter, EncrypterOptions } from './encrypter';
@@ -415,6 +422,7 @@ export type { ProfilingLevelOptions } from './operations/profiling_level';
415
422
  export type { RemoveUserOptions } from './operations/remove_user';
416
423
  export type { RenameOptions } from './operations/rename';
417
424
  export type { RunCommandOptions } from './operations/run_command';
425
+ export type { SearchIndexDescription } from './operations/search_indexes/create';
418
426
  export type { SetProfilingLevelOptions } from './operations/set_profiling_level';
419
427
  export type {
420
428
  CollStats,
@@ -486,6 +494,7 @@ export type {
486
494
  EventEmitterWithState,
487
495
  HostAddress,
488
496
  List,
497
+ MongoDBCollectionNamespace,
489
498
  MongoDBNamespace
490
499
  } from './utils';
491
500
  export type { W, WriteConcernOptions, WriteConcernSettings } from './write_concern';
@@ -325,7 +325,7 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> {
325
325
  /** @internal */
326
326
  topology?: Topology;
327
327
  /** @internal */
328
- readonly mongoLogger: MongoLogger;
328
+ override readonly mongoLogger: MongoLogger;
329
329
  /** @internal */
330
330
  private connectionLock?: Promise<this>;
331
331
 
@@ -471,23 +471,21 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> {
471
471
  }
472
472
  }
473
473
 
474
- const topology = new Topology(options.hosts, options);
474
+ this.topology = new Topology(this, options.hosts, options);
475
475
  // Events can be emitted before initialization is complete so we have to
476
476
  // save the reference to the topology on the client ASAP if the event handlers need to access it
477
- this.topology = topology;
478
- topology.client = this;
479
477
 
480
- topology.once(Topology.OPEN, () => this.emit('open', this));
478
+ this.topology.once(Topology.OPEN, () => this.emit('open', this));
481
479
 
482
480
  for (const event of MONGO_CLIENT_EVENTS) {
483
- topology.on(event, (...args: any[]) => this.emit(event, ...(args as any)));
481
+ this.topology.on(event, (...args: any[]) => this.emit(event, ...(args as any)));
484
482
  }
485
483
 
486
484
  const topologyConnect = async () => {
487
485
  try {
488
- await promisify(callback => topology.connect(options, callback))();
486
+ await promisify(callback => this.topology?.connect(options, callback))();
489
487
  } catch (error) {
490
- topology.close({ force: true });
488
+ this.topology?.close({ force: true });
491
489
  throw error;
492
490
  }
493
491
  };
@@ -774,19 +772,29 @@ export interface MongoOptions
774
772
  /**
775
773
  * # NOTE ABOUT TLS Options
776
774
  *
777
- * If set TLS enabled, equivalent to setting the ssl option.
775
+ * If `tls` is provided as an option, it is equivalent to setting the `ssl` option.
776
+ *
777
+ * NodeJS native TLS options are passed through to the socket and retain their original types.
778
778
  *
779
779
  * ### Additional options:
780
780
  *
781
- * | nodejs option | MongoDB equivalent | type |
782
- * |:---------------------|--------------------------------------------------------- |:---------------------------------------|
783
- * | `ca` | `sslCA`, `tlsCAFile` | `string \| Buffer \| Buffer[]` |
784
- * | `crl` | `sslCRL` | `string \| Buffer \| Buffer[]` |
785
- * | `cert` | `sslCert`, `tlsCertificateFile`, `tlsCertificateKeyFile` | `string \| Buffer \| Buffer[]` |
786
- * | `key` | `sslKey`, `tlsCertificateKeyFile` | `string \| Buffer \| KeyObject[]` |
787
- * | `passphrase` | `sslPass`, `tlsCertificateKeyFilePassword` | `string` |
788
- * | `rejectUnauthorized` | `sslValidate` | `boolean` |
781
+ * | nodejs native option | driver spec compliant option name | legacy option name | driver option type |
782
+ * |:----------------------|:----------------------------------------------|:-------------------|:-------------------|
783
+ * | `ca` | `tlsCAFile` | `sslCA` | `string` |
784
+ * | `crl` | N/A | `sslCRL` | `string` |
785
+ * | `cert` | `tlsCertificateFile`, `tlsCertificateKeyFile` | `sslCert` | `string` |
786
+ * | `key` | `tlsCertificateKeyFile` | `sslKey` | `string` |
787
+ * | `passphrase` | `tlsCertificateKeyFilePassword` | `sslPass` | `string` |
788
+ * | `rejectUnauthorized` | `tlsAllowInvalidCertificates` | `sslValidate` | `boolean` |
789
+ * | `checkServerIdentity` | `tlsAllowInvalidHostnames` | N/A | `boolean` |
790
+ * | see note below | `tlsInsecure` | N/A | `boolean` |
791
+ *
792
+ * If `tlsInsecure` is set to `true`, then it will set the node native options `checkServerIdentity`
793
+ * to a no-op and `rejectUnauthorized` to `false`.
789
794
  *
795
+ * If `tlsInsecure` is set to `false`, then it will set the node native options `checkServerIdentity`
796
+ * to a no-op and `rejectUnauthorized` to the inverse value of `tlsAllowInvalidCertificates`. If
797
+ * `tlsAllowInvalidCertificates` is not set, then `rejectUnauthorized` will be set to `true`.
790
798
  */
791
799
  tls: boolean;
792
800
 
@@ -12,6 +12,7 @@ import type {
12
12
  ObjectId,
13
13
  Timestamp
14
14
  } from './bson';
15
+ import type { MongoLoggableComponent, MongoLogger } from './mongo_logger';
15
16
  import type { Sort } from './sort';
16
17
 
17
18
  /** @internal */
@@ -397,8 +398,21 @@ export declare interface TypedEventEmitter<Events extends EventsDescription> ext
397
398
  * Typescript type safe event emitter
398
399
  * @public
399
400
  */
400
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
401
- export class TypedEventEmitter<Events extends EventsDescription> extends EventEmitter {}
401
+
402
+ export class TypedEventEmitter<Events extends EventsDescription> extends EventEmitter {
403
+ /** @internal */
404
+ protected mongoLogger?: MongoLogger;
405
+ /** @internal */
406
+ protected component?: MongoLoggableComponent;
407
+ /** @internal */
408
+ protected emitAndLog<EventKey extends keyof Events>(
409
+ event: EventKey | symbol,
410
+ ...args: Parameters<Events[EventKey]>
411
+ ): void {
412
+ this.emit(event, ...args);
413
+ if (this.component) this.mongoLogger?.debug(this.component, args[0]);
414
+ }
415
+ }
402
416
 
403
417
  /** @public */
404
418
  export class CancellationToken extends TypedEventEmitter<{ cancel(): void }> {}
@@ -1,6 +1,11 @@
1
1
  import type { Document } from '../bson';
2
+ import {
3
+ MIN_SUPPORTED_QE_SERVER_VERSION,
4
+ MIN_SUPPORTED_QE_WIRE_VERSION
5
+ } from '../cmap/wire_protocol/constants';
2
6
  import { Collection } from '../collection';
3
7
  import type { Db } from '../db';
8
+ import { MongoCompatibilityError } from '../error';
4
9
  import type { PkFactory } from '../mongo_client';
5
10
  import type { Server } from '../sdam/server';
6
11
  import type { ClientSession } from '../sessions';
@@ -41,6 +46,8 @@ export interface TimeSeriesCollectionOptions extends Document {
41
46
  timeField: string;
42
47
  metaField?: string;
43
48
  granularity?: 'seconds' | 'minutes' | 'hours' | string;
49
+ bucketMaxSpanSeconds?: number;
50
+ bucketRoundingSeconds?: number;
44
51
  }
45
52
 
46
53
  /** @public
@@ -55,8 +62,6 @@ export interface ClusteredCollectionOptions extends Document {
55
62
 
56
63
  /** @public */
57
64
  export interface CreateCollectionOptions extends CommandOperationOptions {
58
- /** Returns an error if the collection does not exist */
59
- strict?: boolean;
60
65
  /** Create a capped collection */
61
66
  capped?: boolean;
62
67
  /** @deprecated Create an index on the _id field of the document. This option is deprecated in MongoDB 3.2+ and will be removed once no longer supported by the server. */
@@ -98,6 +103,10 @@ export interface CreateCollectionOptions extends CommandOperationOptions {
98
103
  changeStreamPreAndPostImages?: { enabled: boolean };
99
104
  }
100
105
 
106
+ /* @internal */
107
+ const INVALID_QE_VERSION =
108
+ 'Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption.';
109
+
101
110
  /** @internal */
102
111
  export class CreateCollectionOperation extends CommandOperation<Collection> {
103
112
  override options: CreateCollectionOptions;
@@ -124,15 +133,20 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
124
133
 
125
134
  const encryptedFields: Document | undefined =
126
135
  options.encryptedFields ??
127
- db.s.client.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
136
+ db.client.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
128
137
 
129
138
  if (encryptedFields) {
139
+ // Creating a QE collection required min server of 7.0.0
140
+ if (server.description.maxWireVersion < MIN_SUPPORTED_QE_WIRE_VERSION) {
141
+ throw new MongoCompatibilityError(
142
+ `${INVALID_QE_VERSION} The minimum server version required is ${MIN_SUPPORTED_QE_SERVER_VERSION}`
143
+ );
144
+ }
130
145
  // Create auxilliary collections for queryable encryption support.
131
146
  const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
132
- const eccCollection = encryptedFields.eccCollection ?? `enxcol_.${name}.ecc`;
133
147
  const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
134
148
 
135
- for (const collectionName of [escCollection, eccCollection, ecocCollection]) {
149
+ for (const collectionName of [escCollection, ecocCollection]) {
136
150
  const createOp = new CreateCollectionOperation(db, collectionName, {
137
151
  clusteredIndex: {
138
152
  key: { _id: 1 },
@@ -36,7 +36,7 @@ export class DropCollectionOperation extends CommandOperation<boolean> {
36
36
  const options = this.options;
37
37
  const name = this.name;
38
38
 
39
- const encryptedFieldsMap = db.s.client.options.autoEncryption?.encryptedFieldsMap;
39
+ const encryptedFieldsMap = db.client.options.autoEncryption?.encryptedFieldsMap;
40
40
  let encryptedFields: Document | undefined =
41
41
  options.encryptedFields ?? encryptedFieldsMap?.[`${db.databaseName}.${name}`];
42
42
 
@@ -53,10 +53,9 @@ export class DropCollectionOperation extends CommandOperation<boolean> {
53
53
 
54
54
  if (encryptedFields) {
55
55
  const escCollection = encryptedFields.escCollection || `enxcol_.${name}.esc`;
56
- const eccCollection = encryptedFields.eccCollection || `enxcol_.${name}.ecc`;
57
56
  const ecocCollection = encryptedFields.ecocCollection || `enxcol_.${name}.ecoc`;
58
57
 
59
- for (const collectionName of [escCollection, eccCollection, ecocCollection]) {
58
+ for (const collectionName of [escCollection, ecocCollection]) {
60
59
  // Drop auxilliary collections, ignoring potential NamespaceNotFound errors.
61
60
  const dropOp = new DropCollectionOperation(db, collectionName);
62
61
  try {