mongodb 6.5.0 → 6.6.0-dev.20240504.sha.2609953

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 (207) hide show
  1. package/README.md +9 -9
  2. package/lib/admin.js +9 -9
  3. package/lib/admin.js.map +1 -1
  4. package/lib/bson.js +33 -22
  5. package/lib/bson.js.map +1 -1
  6. package/lib/bulk/common.js +13 -12
  7. package/lib/bulk/common.js.map +1 -1
  8. package/lib/change_stream.js +28 -18
  9. package/lib/change_stream.js.map +1 -1
  10. package/lib/client-side-encryption/auto_encrypter.js +2 -2
  11. package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
  12. package/lib/client-side-encryption/client_encryption.js +6 -6
  13. package/lib/client-side-encryption/client_encryption.js.map +1 -1
  14. package/lib/client-side-encryption/providers/aws.js +13 -10
  15. package/lib/client-side-encryption/providers/aws.js.map +1 -1
  16. package/lib/client-side-encryption/providers/azure.js +6 -3
  17. package/lib/client-side-encryption/providers/azure.js.map +1 -1
  18. package/lib/cmap/auth/aws_temporary_credentials.js +140 -0
  19. package/lib/cmap/auth/aws_temporary_credentials.js.map +1 -0
  20. package/lib/cmap/auth/gssapi.js +7 -6
  21. package/lib/cmap/auth/gssapi.js.map +1 -1
  22. package/lib/cmap/auth/mongodb_aws.js +8 -101
  23. package/lib/cmap/auth/mongodb_aws.js.map +1 -1
  24. package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js +1 -1
  25. package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js.map +1 -1
  26. package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js +2 -1
  27. package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js.map +1 -1
  28. package/lib/cmap/auth/mongodb_oidc/service_workflow.js +1 -1
  29. package/lib/cmap/auth/mongodb_oidc/service_workflow.js.map +1 -1
  30. package/lib/cmap/auth/scram.js +2 -2
  31. package/lib/cmap/auth/scram.js.map +1 -1
  32. package/lib/cmap/commands.js +24 -111
  33. package/lib/cmap/commands.js.map +1 -1
  34. package/lib/cmap/connect.js +4 -4
  35. package/lib/cmap/connect.js.map +1 -1
  36. package/lib/cmap/connection.js +61 -36
  37. package/lib/cmap/connection.js.map +1 -1
  38. package/lib/cmap/connection_pool.js +22 -13
  39. package/lib/cmap/connection_pool.js.map +1 -1
  40. package/lib/cmap/handshake/client_metadata.js +2 -2
  41. package/lib/cmap/handshake/client_metadata.js.map +1 -1
  42. package/lib/cmap/wire_protocol/compression.js +8 -8
  43. package/lib/cmap/wire_protocol/compression.js.map +1 -1
  44. package/lib/cmap/wire_protocol/on_demand/document.js +218 -0
  45. package/lib/cmap/wire_protocol/on_demand/document.js.map +1 -0
  46. package/lib/cmap/wire_protocol/responses.js +184 -0
  47. package/lib/cmap/wire_protocol/responses.js.map +1 -0
  48. package/lib/collection.js +42 -38
  49. package/lib/collection.js.map +1 -1
  50. package/lib/connection_string.js +4 -6
  51. package/lib/connection_string.js.map +1 -1
  52. package/lib/cursor/abstract_cursor.js +76 -43
  53. package/lib/cursor/abstract_cursor.js.map +1 -1
  54. package/lib/cursor/aggregation_cursor.js +16 -33
  55. package/lib/cursor/aggregation_cursor.js.map +1 -1
  56. package/lib/cursor/find_cursor.js +36 -18
  57. package/lib/cursor/find_cursor.js.map +1 -1
  58. package/lib/cursor/run_command_cursor.js +3 -2
  59. package/lib/cursor/run_command_cursor.js.map +1 -1
  60. package/lib/db.js +15 -19
  61. package/lib/db.js.map +1 -1
  62. package/lib/deps.js +31 -26
  63. package/lib/deps.js.map +1 -1
  64. package/lib/encrypter.js +14 -5
  65. package/lib/encrypter.js.map +1 -1
  66. package/lib/error.js +4 -3
  67. package/lib/error.js.map +1 -1
  68. package/lib/gridfs/download.js +19 -14
  69. package/lib/gridfs/download.js.map +1 -1
  70. package/lib/gridfs/index.js.map +1 -1
  71. package/lib/gridfs/upload.js +6 -1
  72. package/lib/gridfs/upload.js.map +1 -1
  73. package/lib/index.js.map +1 -1
  74. package/lib/mongo_client.js +11 -7
  75. package/lib/mongo_client.js.map +1 -1
  76. package/lib/mongo_logger.js +3 -0
  77. package/lib/mongo_logger.js.map +1 -1
  78. package/lib/operations/aggregate.js +2 -1
  79. package/lib/operations/aggregate.js.map +1 -1
  80. package/lib/operations/command.js +1 -1
  81. package/lib/operations/command.js.map +1 -1
  82. package/lib/operations/create_collection.js +1 -1
  83. package/lib/operations/create_collection.js.map +1 -1
  84. package/lib/operations/delete.js +4 -3
  85. package/lib/operations/delete.js.map +1 -1
  86. package/lib/operations/drop.js +1 -1
  87. package/lib/operations/drop.js.map +1 -1
  88. package/lib/operations/execute_operation.js +23 -8
  89. package/lib/operations/execute_operation.js.map +1 -1
  90. package/lib/operations/find.js +4 -4
  91. package/lib/operations/find.js.map +1 -1
  92. package/lib/operations/get_more.js +2 -1
  93. package/lib/operations/get_more.js.map +1 -1
  94. package/lib/operations/indexes.js +29 -121
  95. package/lib/operations/indexes.js.map +1 -1
  96. package/lib/operations/insert.js +3 -3
  97. package/lib/operations/insert.js.map +1 -1
  98. package/lib/operations/kill_cursors.js +3 -1
  99. package/lib/operations/kill_cursors.js.map +1 -1
  100. package/lib/operations/list_collections.js +1 -1
  101. package/lib/operations/list_collections.js.map +1 -1
  102. package/lib/operations/list_databases.js +1 -1
  103. package/lib/operations/list_databases.js.map +1 -1
  104. package/lib/operations/operation.js.map +1 -1
  105. package/lib/operations/run_command.js +4 -2
  106. package/lib/operations/run_command.js.map +1 -1
  107. package/lib/operations/search_indexes/create.js.map +1 -1
  108. package/lib/operations/stats.js +1 -1
  109. package/lib/operations/stats.js.map +1 -1
  110. package/lib/operations/update.js +1 -1
  111. package/lib/operations/update.js.map +1 -1
  112. package/lib/sdam/common.js.map +1 -1
  113. package/lib/sdam/monitor.js +139 -42
  114. package/lib/sdam/monitor.js.map +1 -1
  115. package/lib/sdam/server.js +5 -15
  116. package/lib/sdam/server.js.map +1 -1
  117. package/lib/sdam/server_description.js +1 -0
  118. package/lib/sdam/server_description.js.map +1 -1
  119. package/lib/sdam/server_selection.js +1 -1
  120. package/lib/sdam/server_selection.js.map +1 -1
  121. package/lib/sdam/srv_polling.js +2 -1
  122. package/lib/sdam/srv_polling.js.map +1 -1
  123. package/lib/sdam/topology.js +67 -54
  124. package/lib/sdam/topology.js.map +1 -1
  125. package/lib/sdam/topology_description.js +10 -0
  126. package/lib/sdam/topology_description.js.map +1 -1
  127. package/lib/sessions.js +133 -93
  128. package/lib/sessions.js.map +1 -1
  129. package/lib/timeout.js +77 -0
  130. package/lib/timeout.js.map +1 -0
  131. package/lib/utils.js +61 -28
  132. package/lib/utils.js.map +1 -1
  133. package/mongodb.d.ts +150 -38
  134. package/package.json +17 -14
  135. package/src/admin.ts +9 -9
  136. package/src/bson.ts +14 -0
  137. package/src/bulk/common.ts +3 -2
  138. package/src/change_stream.ts +39 -30
  139. package/src/client-side-encryption/auto_encrypter.ts +2 -2
  140. package/src/client-side-encryption/client_encryption.ts +6 -6
  141. package/src/client-side-encryption/providers/aws.ts +17 -10
  142. package/src/client-side-encryption/providers/azure.ts +5 -3
  143. package/src/cmap/auth/aws_temporary_credentials.ts +169 -0
  144. package/src/cmap/auth/gssapi.ts +9 -11
  145. package/src/cmap/auth/mongodb_aws.ts +19 -126
  146. package/src/cmap/auth/mongodb_oidc/aws_service_workflow.ts +1 -1
  147. package/src/cmap/auth/mongodb_oidc/callback_lock_cache.ts +2 -1
  148. package/src/cmap/auth/mongodb_oidc/service_workflow.ts +1 -1
  149. package/src/cmap/auth/scram.ts +2 -2
  150. package/src/cmap/commands.ts +28 -132
  151. package/src/cmap/connect.ts +4 -4
  152. package/src/cmap/connection.ts +107 -43
  153. package/src/cmap/connection_pool.ts +32 -29
  154. package/src/cmap/handshake/client_metadata.ts +2 -5
  155. package/src/cmap/wire_protocol/compression.ts +11 -13
  156. package/src/cmap/wire_protocol/on_demand/document.ts +338 -0
  157. package/src/cmap/wire_protocol/responses.ts +237 -0
  158. package/src/collection.ts +87 -58
  159. package/src/connection_string.ts +9 -7
  160. package/src/cursor/abstract_cursor.ts +102 -38
  161. package/src/cursor/aggregation_cursor.ts +32 -34
  162. package/src/cursor/find_cursor.ts +33 -21
  163. package/src/cursor/list_search_indexes_cursor.ts +1 -1
  164. package/src/cursor/run_command_cursor.ts +3 -2
  165. package/src/db.ts +42 -21
  166. package/src/deps.ts +52 -40
  167. package/src/encrypter.ts +14 -5
  168. package/src/error.ts +9 -3
  169. package/src/gridfs/download.ts +19 -31
  170. package/src/gridfs/index.ts +2 -0
  171. package/src/gridfs/upload.ts +11 -8
  172. package/src/index.ts +13 -5
  173. package/src/mongo_client.ts +21 -15
  174. package/src/mongo_logger.ts +3 -0
  175. package/src/mongo_types.ts +1 -1
  176. package/src/operations/aggregate.ts +2 -1
  177. package/src/operations/command.ts +1 -1
  178. package/src/operations/create_collection.ts +7 -2
  179. package/src/operations/delete.ts +4 -3
  180. package/src/operations/drop.ts +1 -1
  181. package/src/operations/execute_operation.ts +29 -10
  182. package/src/operations/find.ts +13 -14
  183. package/src/operations/get_more.ts +9 -1
  184. package/src/operations/indexes.ts +103 -176
  185. package/src/operations/insert.ts +2 -2
  186. package/src/operations/kill_cursors.ts +3 -2
  187. package/src/operations/list_collections.ts +5 -1
  188. package/src/operations/list_databases.ts +1 -1
  189. package/src/operations/operation.ts +3 -0
  190. package/src/operations/run_command.ts +6 -4
  191. package/src/operations/search_indexes/create.ts +4 -1
  192. package/src/operations/stats.ts +1 -1
  193. package/src/operations/update.ts +7 -7
  194. package/src/sdam/common.ts +8 -2
  195. package/src/sdam/monitor.ts +178 -61
  196. package/src/sdam/server.ts +27 -20
  197. package/src/sdam/server_description.ts +8 -3
  198. package/src/sdam/server_selection.ts +2 -3
  199. package/src/sdam/srv_polling.ts +3 -2
  200. package/src/sdam/topology.ts +114 -117
  201. package/src/sdam/topology_description.ts +14 -4
  202. package/src/sessions.ts +168 -148
  203. package/src/timeout.ts +96 -0
  204. package/src/utils.ts +85 -32
  205. package/lib/operations/common_functions.js +0 -38
  206. package/lib/operations/common_functions.js.map +0 -1
  207. package/src/operations/common_functions.ts +0 -79
@@ -38,6 +38,7 @@ import {
38
38
  type MongoDBNamespace,
39
39
  now,
40
40
  once,
41
+ squashError,
41
42
  uuidV4
42
43
  } from '../utils';
43
44
  import type { WriteConcern } from '../write_concern';
@@ -53,7 +54,7 @@ import {
53
54
  OpMsgRequest,
54
55
  type OpMsgResponse,
55
56
  OpQueryRequest,
56
- type OpQueryResponse,
57
+ type OpReply,
57
58
  type WriteProtocolMessageType
58
59
  } from './commands';
59
60
  import type { Stream } from './connect';
@@ -61,6 +62,11 @@ import type { ClientMetadata } from './handshake/client_metadata';
61
62
  import { StreamDescription, type StreamDescriptionOptions } from './stream_description';
62
63
  import { type CompressorName, decompressResponse } from './wire_protocol/compression';
63
64
  import { onData } from './wire_protocol/on_data';
65
+ import {
66
+ isErrorResponse,
67
+ MongoDBResponse,
68
+ type MongoDBResponseConstructor
69
+ } from './wire_protocol/responses';
64
70
  import { getReadPreference, isSharded } from './wire_protocol/shared';
65
71
 
66
72
  /** @internal */
@@ -324,7 +330,8 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
324
330
 
325
331
  this.socket.destroy();
326
332
  this.error = error;
327
- this.dataEvents?.throw(error).then(undefined, () => null); // squash unhandled rejection
333
+ // eslint-disable-next-line github/no-then
334
+ this.dataEvents?.throw(error).then(undefined, squashError);
328
335
  this.closed = true;
329
336
  this.emit(Connection.CLOSE);
330
337
  }
@@ -410,7 +417,11 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
410
417
  return message;
411
418
  }
412
419
 
413
- private async *sendWire(message: WriteProtocolMessageType, options: CommandOptions) {
420
+ private async *sendWire(
421
+ message: WriteProtocolMessageType,
422
+ options: CommandOptions,
423
+ responseType?: MongoDBResponseConstructor
424
+ ): AsyncGenerator<MongoDBResponse> {
414
425
  this.throwIfAborted();
415
426
 
416
427
  if (typeof options.socketTimeoutMS === 'number') {
@@ -426,7 +437,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
426
437
  });
427
438
 
428
439
  if (options.noResponse) {
429
- yield { ok: 1 };
440
+ yield MongoDBResponse.empty;
430
441
  return;
431
442
  }
432
443
 
@@ -434,21 +445,14 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
434
445
 
435
446
  for await (const response of this.readMany()) {
436
447
  this.socket.setTimeout(0);
437
- response.parse(options);
448
+ const bson = response.parse();
438
449
 
439
- const [document] = response.documents;
440
-
441
- if (!Buffer.isBuffer(document)) {
442
- const { session } = options;
443
- if (session) {
444
- updateSessionFromResponse(session, document);
445
- }
446
-
447
- if (document.$clusterTime) {
448
- this.clusterTime = document.$clusterTime;
449
- this.emit(Connection.CLUSTER_TIME_RECEIVED, document.$clusterTime);
450
- }
451
- }
450
+ const document =
451
+ responseType == null
452
+ ? new MongoDBResponse(bson)
453
+ : isErrorResponse(bson)
454
+ ? new MongoDBResponse(bson)
455
+ : new responseType(bson);
452
456
 
453
457
  yield document;
454
458
  this.throwIfAborted();
@@ -467,7 +471,8 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
467
471
  private async *sendCommand(
468
472
  ns: MongoDBNamespace,
469
473
  command: Document,
470
- options: CommandOptions = {}
474
+ options: CommandOptions,
475
+ responseType?: MongoDBResponseConstructor
471
476
  ) {
472
477
  const message = this.prepareCommand(ns.db, command, options);
473
478
 
@@ -483,19 +488,41 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
483
488
  );
484
489
  }
485
490
 
486
- let document;
491
+ // If `documentsReturnedIn` not set or raw is not enabled, use input bson options
492
+ // Otherwise, support raw flag. Raw only works for cursors that hardcode firstBatch/nextBatch fields
493
+ const bsonOptions =
494
+ options.documentsReturnedIn == null || !options.raw
495
+ ? options
496
+ : {
497
+ ...options,
498
+ raw: false,
499
+ fieldsAsRaw: { [options.documentsReturnedIn]: true }
500
+ };
501
+
502
+ /** MongoDBResponse instance or subclass */
503
+ let document: MongoDBResponse | undefined = undefined;
504
+ /** Cached result of a toObject call */
505
+ let object: Document | undefined = undefined;
487
506
  try {
488
507
  this.throwIfAborted();
489
- for await (document of this.sendWire(message, options)) {
490
- if (!Buffer.isBuffer(document) && document.writeConcernError) {
491
- throw new MongoWriteConcernError(document.writeConcernError, document);
508
+ for await (document of this.sendWire(message, options, responseType)) {
509
+ object = undefined;
510
+ if (options.session != null) {
511
+ updateSessionFromResponse(options.session, document);
512
+ }
513
+
514
+ if (document.$clusterTime) {
515
+ this.clusterTime = document.$clusterTime;
516
+ this.emit(Connection.CLUSTER_TIME_RECEIVED, document.$clusterTime);
517
+ }
518
+
519
+ if (document.has('writeConcernError')) {
520
+ object ??= document.toObject(bsonOptions);
521
+ throw new MongoWriteConcernError(object.writeConcernError, object);
492
522
  }
493
523
 
494
- if (
495
- !Buffer.isBuffer(document) &&
496
- (document.ok === 0 || document.$err || document.errmsg || document.code)
497
- ) {
498
- throw new MongoServerError(document);
524
+ if (document.isError) {
525
+ throw new MongoServerError((object ??= document.toObject(bsonOptions)));
499
526
  }
500
527
 
501
528
  if (this.shouldEmitAndLogCommand) {
@@ -507,14 +534,19 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
507
534
  new CommandSucceededEvent(
508
535
  this,
509
536
  message,
510
- options.noResponse ? undefined : document,
537
+ options.noResponse ? undefined : (object ??= document.toObject(bsonOptions)),
511
538
  started,
512
539
  this.description.serverConnectionId
513
540
  )
514
541
  );
515
542
  }
516
543
 
517
- yield document;
544
+ if (responseType == null) {
545
+ yield (object ??= document.toObject(bsonOptions));
546
+ } else {
547
+ yield document;
548
+ }
549
+
518
550
  this.throwIfAborted();
519
551
  }
520
552
  } catch (error) {
@@ -528,7 +560,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
528
560
  new CommandSucceededEvent(
529
561
  this,
530
562
  message,
531
- options.noResponse ? undefined : document,
563
+ options.noResponse ? undefined : (object ??= document?.toObject(bsonOptions)),
532
564
  started,
533
565
  this.description.serverConnectionId
534
566
  )
@@ -553,13 +585,27 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
553
585
  }
554
586
  }
555
587
 
588
+ public async command<T extends MongoDBResponseConstructor>(
589
+ ns: MongoDBNamespace,
590
+ command: Document,
591
+ options: CommandOptions | undefined,
592
+ responseType: T | undefined
593
+ ): Promise<typeof responseType extends undefined ? Document : InstanceType<T>>;
594
+
595
+ public async command(
596
+ ns: MongoDBNamespace,
597
+ command: Document,
598
+ options?: CommandOptions
599
+ ): Promise<Document>;
600
+
556
601
  public async command(
557
602
  ns: MongoDBNamespace,
558
603
  command: Document,
559
- options: CommandOptions = {}
604
+ options: CommandOptions = {},
605
+ responseType?: MongoDBResponseConstructor
560
606
  ): Promise<Document> {
561
607
  this.throwIfAborted();
562
- for await (const document of this.sendCommand(ns, command, options)) {
608
+ for await (const document of this.sendCommand(ns, command, options, responseType)) {
563
609
  return document;
564
610
  }
565
611
  throw new MongoUnexpectedServerResponseError('Unable to get response from server');
@@ -579,7 +625,8 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
579
625
  }
580
626
  throw new MongoUnexpectedServerResponseError('Server ended moreToCome unexpectedly');
581
627
  };
582
- exhaustLoop().catch(replyListener);
628
+ // eslint-disable-next-line github/no-then
629
+ exhaustLoop().then(undefined, replyListener);
583
630
  }
584
631
 
585
632
  private throwIfAborted() {
@@ -607,7 +654,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
607
654
  const buffer = Buffer.concat(await finalCommand.toBin());
608
655
 
609
656
  if (this.socket.write(buffer)) return;
610
- return once(this.socket, 'drain');
657
+ return await once(this.socket, 'drain');
611
658
  }
612
659
 
613
660
  /**
@@ -619,7 +666,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
619
666
  *
620
667
  * Note that `for-await` loops call `return` automatically when the loop is exited.
621
668
  */
622
- private async *readMany(): AsyncGenerator<OpMsgResponse | OpQueryResponse> {
669
+ private async *readMany(): AsyncGenerator<OpMsgResponse | OpReply> {
623
670
  try {
624
671
  this.dataEvents = onData(this.messageStream);
625
672
  for await (const message of this.dataEvents) {
@@ -684,21 +731,38 @@ export class CryptoConnection extends Connection {
684
731
  this.autoEncrypter = options.autoEncrypter;
685
732
  }
686
733
 
687
- /** @internal @override */
688
- override async command(
734
+ public override async command<T extends MongoDBResponseConstructor>(
735
+ ns: MongoDBNamespace,
736
+ command: Document,
737
+ options: CommandOptions | undefined,
738
+ responseType: T
739
+ ): Promise<InstanceType<T>>;
740
+
741
+ public override async command(
742
+ ns: MongoDBNamespace,
743
+ command: Document,
744
+ options?: CommandOptions
745
+ ): Promise<Document>;
746
+
747
+ override async command<T extends MongoDBResponseConstructor>(
689
748
  ns: MongoDBNamespace,
690
749
  cmd: Document,
691
- options: CommandOptions
750
+ options?: CommandOptions,
751
+ _responseType?: T | undefined
692
752
  ): Promise<Document> {
693
753
  const { autoEncrypter } = this;
694
754
  if (!autoEncrypter) {
695
- throw new MongoMissingDependencyError('No AutoEncrypter available for encryption');
755
+ // TODO(NODE-6065): throw a MongoRuntimeError in Node V7
756
+ // @ts-expect-error No cause provided because there is no underlying error.
757
+ throw new MongoMissingDependencyError('No AutoEncrypter available for encryption', {
758
+ dependencyName: 'n/a'
759
+ });
696
760
  }
697
761
 
698
762
  const serverWireVersion = maxWireVersion(this);
699
763
  if (serverWireVersion === 0) {
700
764
  // This means the initial handshake hasn't happened yet
701
- return super.command(ns, cmd, options);
765
+ return await super.command<T>(ns, cmd, options, undefined);
702
766
  }
703
767
 
704
768
  if (serverWireVersion < 8) {
@@ -732,8 +796,8 @@ export class CryptoConnection extends Connection {
732
796
  }
733
797
  }
734
798
 
735
- const response = await super.command(ns, encrypted, options);
799
+ const response = await super.command<T>(ns, encrypted, options, undefined);
736
800
 
737
- return autoEncrypter.decrypt(response, options);
801
+ return await autoEncrypter.decrypt(response, options);
738
802
  }
739
803
  }
@@ -26,13 +26,8 @@ import {
26
26
  } from '../error';
27
27
  import { CancellationToken, TypedEventEmitter } from '../mongo_types';
28
28
  import type { Server } from '../sdam/server';
29
- import {
30
- type Callback,
31
- List,
32
- makeCounter,
33
- promiseWithResolvers,
34
- TimeoutController
35
- } from '../utils';
29
+ import { Timeout, TimeoutError } from '../timeout';
30
+ import { type Callback, List, makeCounter, promiseWithResolvers } from '../utils';
36
31
  import { connect } from './connect';
37
32
  import { Connection, type ConnectionEvents, type ConnectionOptions } from './connection';
38
33
  import {
@@ -107,7 +102,7 @@ export interface ConnectionPoolOptions extends Omit<ConnectionOptions, 'id' | 'g
107
102
  export interface WaitQueueMember {
108
103
  resolve: (conn: Connection) => void;
109
104
  reject: (err: AnyError) => void;
110
- timeoutController: TimeoutController;
105
+ timeout: Timeout;
111
106
  [kCancelled]?: boolean;
112
107
  }
113
108
 
@@ -368,33 +363,40 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
368
363
  const waitQueueTimeoutMS = this.options.waitQueueTimeoutMS;
369
364
 
370
365
  const { promise, resolve, reject } = promiseWithResolvers<Connection>();
366
+
367
+ const timeout = Timeout.expires(waitQueueTimeoutMS);
368
+
371
369
  const waitQueueMember: WaitQueueMember = {
372
370
  resolve,
373
371
  reject,
374
- timeoutController: new TimeoutController(waitQueueTimeoutMS)
372
+ timeout
375
373
  };
376
- waitQueueMember.timeoutController.signal.addEventListener('abort', () => {
377
- waitQueueMember[kCancelled] = true;
378
- waitQueueMember.timeoutController.clear();
379
374
 
380
- this.emitAndLog(
381
- ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
382
- new ConnectionCheckOutFailedEvent(this, 'timeout')
383
- );
384
- waitQueueMember.reject(
385
- new WaitQueueTimeoutError(
375
+ this[kWaitQueue].push(waitQueueMember);
376
+ process.nextTick(() => this.processWaitQueue());
377
+
378
+ try {
379
+ return await Promise.race([promise, waitQueueMember.timeout]);
380
+ } catch (error) {
381
+ if (TimeoutError.is(error)) {
382
+ waitQueueMember[kCancelled] = true;
383
+
384
+ waitQueueMember.timeout.clear();
385
+
386
+ this.emitAndLog(
387
+ ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
388
+ new ConnectionCheckOutFailedEvent(this, 'timeout')
389
+ );
390
+ const timeoutError = new WaitQueueTimeoutError(
386
391
  this.loadBalanced
387
392
  ? this.waitQueueErrorMetrics()
388
393
  : 'Timed out while checking out a connection from connection pool',
389
394
  this.address
390
- )
391
- );
392
- });
393
-
394
- this[kWaitQueue].push(waitQueueMember);
395
- process.nextTick(() => this.processWaitQueue());
396
-
397
- return promise;
395
+ );
396
+ throw timeoutError;
397
+ }
398
+ throw error;
399
+ }
398
400
  }
399
401
 
400
402
  /**
@@ -631,6 +633,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
631
633
  new ConnectionCreatedEvent(this, { id: connectOptions.id })
632
634
  );
633
635
 
636
+ // eslint-disable-next-line github/no-then
634
637
  connect(connectOptions).then(
635
638
  connection => {
636
639
  // The pool might have closed since we started trying to create a connection
@@ -757,7 +760,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
757
760
  ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
758
761
  new ConnectionCheckOutFailedEvent(this, reason, error)
759
762
  );
760
- waitQueueMember.timeoutController.clear();
763
+ waitQueueMember.timeout.clear();
761
764
  this[kWaitQueue].shift();
762
765
  waitQueueMember.reject(error);
763
766
  continue;
@@ -778,7 +781,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
778
781
  ConnectionPool.CONNECTION_CHECKED_OUT,
779
782
  new ConnectionCheckedOutEvent(this, connection)
780
783
  );
781
- waitQueueMember.timeoutController.clear();
784
+ waitQueueMember.timeout.clear();
782
785
 
783
786
  this[kWaitQueue].shift();
784
787
  waitQueueMember.resolve(connection);
@@ -817,7 +820,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
817
820
  waitQueueMember.resolve(connection);
818
821
  }
819
822
 
820
- waitQueueMember.timeoutController.clear();
823
+ waitQueueMember.timeout.clear();
821
824
  }
822
825
  process.nextTick(() => this.processWaitQueue());
823
826
  });
@@ -1,10 +1,10 @@
1
- import { promises as fs } from 'fs';
2
1
  import * as os from 'os';
3
2
  import * as process from 'process';
4
3
 
5
4
  import { BSON, type Document, Int32 } from '../../bson';
6
5
  import { MongoInvalidArgumentError } from '../../error';
7
6
  import type { MongoOptions } from '../../mongo_client';
7
+ import { fileIsAccessible } from '../../utils';
8
8
 
9
9
  // eslint-disable-next-line @typescript-eslint/no-var-requires
10
10
  const NODE_DRIVER_VERSION = require('../../../package.json').version;
@@ -160,10 +160,7 @@ let dockerPromise: Promise<boolean>;
160
160
  /** @internal */
161
161
  async function getContainerMetadata() {
162
162
  const containerMetadata: Record<string, any> = {};
163
- dockerPromise ??= fs.access('/.dockerenv').then(
164
- () => true,
165
- () => false
166
- );
163
+ dockerPromise ??= fileIsAccessible('/.dockerenv');
167
164
  const isDocker = await dockerPromise;
168
165
 
169
166
  const { KUBERNETES_SERVICE_HOST = '' } = process.env;
@@ -8,7 +8,7 @@ import {
8
8
  type MessageHeader,
9
9
  OpCompressedRequest,
10
10
  OpMsgResponse,
11
- OpQueryResponse,
11
+ OpReply,
12
12
  type WriteProtocolMessageType
13
13
  } from '../commands';
14
14
  import { OP_COMPRESSED, OP_MSG } from './constants';
@@ -45,7 +45,7 @@ const ZSTD_COMPRESSION_LEVEL = 3;
45
45
  const zlibInflate = promisify(zlib.inflate.bind(zlib));
46
46
  const zlibDeflate = promisify(zlib.deflate.bind(zlib));
47
47
 
48
- let zstd: typeof ZStandard;
48
+ let zstd: ZStandard;
49
49
  let Snappy: SnappyLib | null = null;
50
50
  function loadSnappy() {
51
51
  if (Snappy == null) {
@@ -67,20 +67,20 @@ export async function compress(
67
67
  switch (options.agreedCompressor) {
68
68
  case 'snappy': {
69
69
  Snappy ??= loadSnappy();
70
- return Snappy.compress(dataToBeCompressed);
70
+ return await Snappy.compress(dataToBeCompressed);
71
71
  }
72
72
  case 'zstd': {
73
73
  loadZstd();
74
74
  if ('kModuleError' in zstd) {
75
75
  throw zstd['kModuleError'];
76
76
  }
77
- return zstd.compress(dataToBeCompressed, ZSTD_COMPRESSION_LEVEL);
77
+ return await zstd.compress(dataToBeCompressed, ZSTD_COMPRESSION_LEVEL);
78
78
  }
79
79
  case 'zlib': {
80
80
  if (options.zlibCompressionLevel) {
81
81
  zlibOptions.level = options.zlibCompressionLevel;
82
82
  }
83
- return zlibDeflate(dataToBeCompressed, zlibOptions);
83
+ return await zlibDeflate(dataToBeCompressed, zlibOptions);
84
84
  }
85
85
  default: {
86
86
  throw new MongoInvalidArgumentError(
@@ -106,17 +106,17 @@ export async function decompress(compressorID: number, compressedData: Buffer):
106
106
  switch (compressorID) {
107
107
  case Compressor.snappy: {
108
108
  Snappy ??= loadSnappy();
109
- return Snappy.uncompress(compressedData, { asBuffer: true });
109
+ return await Snappy.uncompress(compressedData, { asBuffer: true });
110
110
  }
111
111
  case Compressor.zstd: {
112
112
  loadZstd();
113
113
  if ('kModuleError' in zstd) {
114
114
  throw zstd['kModuleError'];
115
115
  }
116
- return zstd.decompress(compressedData);
116
+ return await zstd.decompress(compressedData);
117
117
  }
118
118
  case Compressor.zlib: {
119
- return zlibInflate(compressedData);
119
+ return await zlibInflate(compressedData);
120
120
  }
121
121
  default: {
122
122
  return compressedData;
@@ -163,9 +163,7 @@ export async function compressCommand(
163
163
  *
164
164
  * This method does not parse the response's BSON.
165
165
  */
166
- export async function decompressResponse(
167
- message: Buffer
168
- ): Promise<OpMsgResponse | OpQueryResponse> {
166
+ export async function decompressResponse(message: Buffer): Promise<OpMsgResponse | OpReply> {
169
167
  const messageHeader: MessageHeader = {
170
168
  length: message.readInt32LE(0),
171
169
  requestId: message.readInt32LE(4),
@@ -174,7 +172,7 @@ export async function decompressResponse(
174
172
  };
175
173
 
176
174
  if (messageHeader.opCode !== OP_COMPRESSED) {
177
- const ResponseType = messageHeader.opCode === OP_MSG ? OpMsgResponse : OpQueryResponse;
175
+ const ResponseType = messageHeader.opCode === OP_MSG ? OpMsgResponse : OpReply;
178
176
  const messageBody = message.subarray(MESSAGE_HEADER_SIZE);
179
177
  return new ResponseType(message, messageHeader, messageBody);
180
178
  }
@@ -189,7 +187,7 @@ export async function decompressResponse(
189
187
  const compressedBuffer = message.slice(MESSAGE_HEADER_SIZE + 9);
190
188
 
191
189
  // recalculate based on wrapped opcode
192
- const ResponseType = header.opCode === OP_MSG ? OpMsgResponse : OpQueryResponse;
190
+ const ResponseType = header.opCode === OP_MSG ? OpMsgResponse : OpReply;
193
191
  const messageBody = await decompress(compressorID, compressedBuffer);
194
192
  if (messageBody.length !== header.length) {
195
193
  throw new MongoDecompressionError('Message body and message header must be the same length');