mongodb 3.6.2 → 3.6.3

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.
package/HISTORY.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ <a name="3.6.3"></a>
6
+ ## [3.6.3](https://github.com/mongodb/node-mongodb-native/compare/v3.6.1...v3.6.3) (2020-11-06)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * add peerDependenciesMeta to mark optional deps ([#2606](https://github.com/mongodb/node-mongodb-native/issues/2606)) ([186090e](https://github.com/mongodb/node-mongodb-native/commit/186090e))
12
+ * adds topology discovery for sharded cluster ([f8fd310](https://github.com/mongodb/node-mongodb-native/commit/f8fd310))
13
+ * allow event loop to process during wait queue processing ([#2537](https://github.com/mongodb/node-mongodb-native/issues/2537)) ([4e03dfa](https://github.com/mongodb/node-mongodb-native/commit/4e03dfa))
14
+ * Change socket timeout default to 0 ([#2572](https://github.com/mongodb/node-mongodb-native/issues/2572)) ([89b77ed](https://github.com/mongodb/node-mongodb-native/commit/89b77ed))
15
+ * connection leak if wait queue member cancelled ([cafaa1b](https://github.com/mongodb/node-mongodb-native/commit/cafaa1b))
16
+ * correctly assign username to X509 auth command ([#2587](https://github.com/mongodb/node-mongodb-native/issues/2587)) ([9110a45](https://github.com/mongodb/node-mongodb-native/commit/9110a45))
17
+ * correctly re-establishes pipe destinations ([a6e7caf](https://github.com/mongodb/node-mongodb-native/commit/a6e7caf))
18
+ * Fix test filters and revert mocha version ([#2558](https://github.com/mongodb/node-mongodb-native/issues/2558)) ([0e5c45a](https://github.com/mongodb/node-mongodb-native/commit/0e5c45a))
19
+ * move kerberos client setup from prepare to auth ([#2608](https://github.com/mongodb/node-mongodb-native/issues/2608)) ([033b6e7](https://github.com/mongodb/node-mongodb-native/commit/033b6e7))
20
+ * permit waking async interval with unreliable clock ([e0e11bb](https://github.com/mongodb/node-mongodb-native/commit/e0e11bb))
21
+ * remove geoNear deprecation ([4955a52](https://github.com/mongodb/node-mongodb-native/commit/4955a52))
22
+ * revert use of setImmediate to process.nextTick ([#2611](https://github.com/mongodb/node-mongodb-native/issues/2611)) ([c9f9d5e](https://github.com/mongodb/node-mongodb-native/commit/c9f9d5e))
23
+ * sets primary read preference for writes ([ddcd03d](https://github.com/mongodb/node-mongodb-native/commit/ddcd03d))
24
+ * use options for readPreference in client ([6acced0](https://github.com/mongodb/node-mongodb-native/commit/6acced0))
25
+ * user roles take single string & DDL readPreference tests ([967de13](https://github.com/mongodb/node-mongodb-native/commit/967de13))
26
+
27
+
28
+
5
29
  <a name="3.6.2"></a>
6
30
  ## [3.6.2](https://github.com/mongodb/node-mongodb-native/compare/v3.6.1...v3.6.2) (2020-09-10)
7
31
 
@@ -3,7 +3,6 @@
3
3
  const MongoError = require('./core').MongoError;
4
4
  const Cursor = require('./cursor');
5
5
  const CursorState = require('./core/cursor').CursorState;
6
- const deprecate = require('util').deprecate;
7
6
 
8
7
  /**
9
8
  * @fileOverview The **AggregationCursor** class is an internal class that embodies an aggregation cursor on MongoDB
@@ -225,12 +224,6 @@ class AggregationCursor extends Cursor {
225
224
  // aliases
226
225
  AggregationCursor.prototype.get = AggregationCursor.prototype.toArray;
227
226
 
228
- // deprecated methods
229
- deprecate(
230
- AggregationCursor.prototype.geoNear,
231
- 'The `$geoNear` stage is deprecated in MongoDB 4.0, and removed in version 4.2.'
232
- );
233
-
234
227
  /**
235
228
  * AggregationCursor stream data event, fired for each document in the cursor.
236
229
  *
@@ -437,7 +437,7 @@ function createChangeStreamCursor(self, options) {
437
437
 
438
438
  if (self.pipeDestinations) {
439
439
  const cursorStream = changeStreamCursor.stream(self.streamOptions);
440
- for (let pipeDestination in self.pipeDestinations) {
440
+ for (let pipeDestination of self.pipeDestinations) {
441
441
  cursorStream.pipe(pipeDestination);
442
442
  }
443
443
  }
@@ -32,7 +32,7 @@ class Connection extends EventEmitter {
32
32
  this.id = options.id;
33
33
  this.address = streamIdentifier(stream);
34
34
  this.bson = options.bson;
35
- this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
35
+ this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
36
36
  this.host = options.host || 'localhost';
37
37
  this.port = options.port || 27017;
38
38
  this.monitorCommands =
@@ -95,7 +95,7 @@ const VALID_POOL_OPTIONS = new Set([
95
95
 
96
96
  function resolveOptions(options, defaults) {
97
97
  const newOptions = Array.from(VALID_POOL_OPTIONS).reduce((obj, key) => {
98
- if (options.hasOwnProperty(key)) {
98
+ if (Object.prototype.hasOwnProperty.call(options, key)) {
99
99
  obj[key] = options[key];
100
100
  }
101
101
 
@@ -233,7 +233,7 @@ class ConnectionPool extends EventEmitter {
233
233
  }
234
234
 
235
235
  this[kWaitQueue].push(waitQueueMember);
236
- setImmediate(() => processWaitQueue(this));
236
+ process.nextTick(() => processWaitQueue(this));
237
237
  }
238
238
 
239
239
  /**
@@ -258,7 +258,7 @@ class ConnectionPool extends EventEmitter {
258
258
  destroyConnection(this, connection, reason);
259
259
  }
260
260
 
261
- setImmediate(() => processWaitQueue(this));
261
+ process.nextTick(() => processWaitQueue(this));
262
262
  }
263
263
 
264
264
  /**
@@ -428,7 +428,7 @@ function createConnection(pool, callback) {
428
428
 
429
429
  // otherwise add it to the pool for later acquisition, and try to process the wait queue
430
430
  pool[kConnections].push(connection);
431
- setImmediate(() => processWaitQueue(pool));
431
+ process.nextTick(() => processWaitQueue(pool));
432
432
  });
433
433
  }
434
434
 
@@ -439,7 +439,7 @@ function destroyConnection(pool, connection, reason) {
439
439
  pool[kPermits]++;
440
440
 
441
441
  // destroy the connection
442
- setImmediate(() => connection.destroy());
442
+ process.nextTick(() => connection.destroy());
443
443
  }
444
444
 
445
445
  function processWaitQueue(pool) {
@@ -477,7 +477,7 @@ function processWaitQueue(pool) {
477
477
  if (pool.waitQueueSize && (maxPoolSize <= 0 || pool.totalConnectionCount < maxPoolSize)) {
478
478
  createConnection(pool, (err, connection) => {
479
479
  const waitQueueMember = pool[kWaitQueue].shift();
480
- if (waitQueueMember == null) {
480
+ if (waitQueueMember == null || waitQueueMember[kCancelled]) {
481
481
  if (err == null) {
482
482
  pool[kConnections].push(connection);
483
483
  }
@@ -485,10 +485,6 @@ function processWaitQueue(pool) {
485
485
  return;
486
486
  }
487
487
 
488
- if (waitQueueMember[kCancelled]) {
489
- return;
490
- }
491
-
492
488
  if (err) {
493
489
  pool.emit('connectionCheckOutFailed', new ConnectionCheckOutFailedEvent(pool, err));
494
490
  } else {
@@ -5,88 +5,44 @@ const AuthProvider = require('./auth_provider').AuthProvider;
5
5
  const retrieveKerberos = require('../utils').retrieveKerberos;
6
6
  const MongoError = require('../error').MongoError;
7
7
 
8
- const kGssapiClient = Symbol('GSSAPI_CLIENT');
9
8
  let kerberos;
10
9
 
11
10
  class GSSAPI extends AuthProvider {
12
- prepare(handshakeDoc, authContext, callback) {
13
- const host = authContext.options.host;
14
- const port = authContext.options.port;
15
- const credentials = authContext.credentials;
16
- if (!host || !port || !credentials) {
17
- return callback(
18
- new MongoError(
19
- `Connection must specify: ${host ? 'host' : ''}, ${port ? 'port' : ''}, ${
20
- credentials ? 'host' : 'credentials'
21
- }.`
22
- )
23
- );
24
- }
25
- if (kerberos == null) {
26
- try {
27
- kerberos = retrieveKerberos();
28
- } catch (e) {
29
- return callback(e);
30
- }
31
- }
32
- const username = credentials.username;
33
- const password = credentials.password;
34
- const mechanismProperties = credentials.mechanismProperties;
35
- const serviceName =
36
- mechanismProperties['gssapiservicename'] ||
37
- mechanismProperties['gssapiServiceName'] ||
38
- 'mongodb';
39
- performGssapiCanonicalizeHostName(host, mechanismProperties, (err, host) => {
40
- if (err) return callback(err);
41
- const initOptions = {};
42
- if (password != null) {
43
- Object.assign(initOptions, { user: username, password: password });
44
- }
45
- kerberos.initializeClient(
46
- `${serviceName}${process.platform === 'win32' ? '/' : '@'}${host}`,
47
- initOptions,
48
- (err, client) => {
49
- if (err) return callback(new MongoError(err));
50
- if (client == null) return callback();
51
- this[kGssapiClient] = client;
52
- callback(undefined, handshakeDoc);
53
- }
54
- );
55
- });
56
- }
57
11
  auth(authContext, callback) {
58
12
  const connection = authContext.connection;
59
13
  const credentials = authContext.credentials;
60
14
  if (credentials == null) return callback(new MongoError('credentials required'));
61
15
  const username = credentials.username;
62
- const client = this[kGssapiClient];
63
- if (client == null) return callback(new MongoError('gssapi client missing'));
64
16
  function externalCommand(command, cb) {
65
17
  return connection.command('$external.$cmd', command, cb);
66
18
  }
67
- client.step('', (err, payload) => {
19
+ makeKerberosClient(authContext, (err, client) => {
68
20
  if (err) return callback(err);
69
- externalCommand(saslStart(payload), (err, response) => {
70
- const result = response.result;
21
+ if (client == null) return callback(new MongoError('gssapi client missing'));
22
+ client.step('', (err, payload) => {
71
23
  if (err) return callback(err);
72
- negotiate(client, 10, result.payload, (err, payload) => {
24
+ externalCommand(saslStart(payload), (err, response) => {
73
25
  if (err) return callback(err);
74
- externalCommand(saslContinue(payload, result.conversationId), (err, response) => {
75
- const result = response.result;
26
+ const result = response.result;
27
+ negotiate(client, 10, result.payload, (err, payload) => {
76
28
  if (err) return callback(err);
77
- finalize(client, username, result.payload, (err, payload) => {
29
+ externalCommand(saslContinue(payload, result.conversationId), (err, response) => {
78
30
  if (err) return callback(err);
79
- externalCommand(
80
- {
81
- saslContinue: 1,
82
- conversationId: result.conversationId,
83
- payload
84
- },
85
- (err, result) => {
86
- if (err) return callback(err);
87
- callback(undefined, result);
88
- }
89
- );
31
+ const result = response.result;
32
+ finalize(client, username, result.payload, (err, payload) => {
33
+ if (err) return callback(err);
34
+ externalCommand(
35
+ {
36
+ saslContinue: 1,
37
+ conversationId: result.conversationId,
38
+ payload
39
+ },
40
+ (err, result) => {
41
+ if (err) return callback(err);
42
+ callback(undefined, result);
43
+ }
44
+ );
45
+ });
90
46
  });
91
47
  });
92
48
  });
@@ -96,6 +52,50 @@ class GSSAPI extends AuthProvider {
96
52
  }
97
53
  module.exports = GSSAPI;
98
54
 
55
+ function makeKerberosClient(authContext, callback) {
56
+ const host = authContext.options.host;
57
+ const port = authContext.options.port;
58
+ const credentials = authContext.credentials;
59
+ if (!host || !port || !credentials) {
60
+ return callback(
61
+ new MongoError(
62
+ `Connection must specify: ${host ? 'host' : ''}, ${port ? 'port' : ''}, ${
63
+ credentials ? 'host' : 'credentials'
64
+ }.`
65
+ )
66
+ );
67
+ }
68
+ if (kerberos == null) {
69
+ try {
70
+ kerberos = retrieveKerberos();
71
+ } catch (e) {
72
+ return callback(e);
73
+ }
74
+ }
75
+ const username = credentials.username;
76
+ const password = credentials.password;
77
+ const mechanismProperties = credentials.mechanismProperties;
78
+ const serviceName =
79
+ mechanismProperties['gssapiservicename'] ||
80
+ mechanismProperties['gssapiServiceName'] ||
81
+ 'mongodb';
82
+ performGssapiCanonicalizeHostName(host, mechanismProperties, (err, host) => {
83
+ if (err) return callback(err);
84
+ const initOptions = {};
85
+ if (password != null) {
86
+ Object.assign(initOptions, { user: username, password: password });
87
+ }
88
+ kerberos.initializeClient(
89
+ `${serviceName}${process.platform === 'win32' ? '/' : '@'}${host}`,
90
+ initOptions,
91
+ (err, client) => {
92
+ if (err) return callback(new MongoError(err));
93
+ callback(null, client);
94
+ }
95
+ );
96
+ });
97
+ }
98
+
99
99
  function saslStart(payload) {
100
100
  return {
101
101
  saslStart: 1,
@@ -26,7 +26,7 @@ class X509 extends AuthProvider {
26
26
  function x509AuthenticateCommand(credentials) {
27
27
  const command = { authenticate: 1, mechanism: 'MONGODB-X509' };
28
28
  if (credentials.username) {
29
- Object.apply(command, { user: credentials.username });
29
+ Object.assign(command, { user: credentials.username });
30
30
  }
31
31
 
32
32
  return command;
@@ -263,7 +263,7 @@ function makeConnection(family, options, cancellationToken, _callback) {
263
263
  : typeof options.connectTimeoutMS === 'number'
264
264
  ? options.connectTimeoutMS
265
265
  : 30000;
266
- const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
266
+ const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
267
267
  const rejectUnauthorized =
268
268
  typeof options.rejectUnauthorized === 'boolean' ? options.rejectUnauthorized : true;
269
269
 
@@ -69,7 +69,7 @@ class Connection extends EventEmitter {
69
69
  * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
70
70
  * @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
71
71
  * @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
72
- * @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
72
+ * @param {number} [options.socketTimeout=0] TCP Socket timeout setting
73
73
  * @param {boolean} [options.promoteLongs] Convert Long values from the db into Numbers if they fit into 53 bits
74
74
  * @param {boolean} [options.promoteValues] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
75
75
  * @param {boolean} [options.promoteBuffers] Promotes Binary BSON values to native Node Buffers.
@@ -92,7 +92,7 @@ class Connection extends EventEmitter {
92
92
 
93
93
  this.port = options.port || 27017;
94
94
  this.host = options.host || 'localhost';
95
- this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
95
+ this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
96
96
 
97
97
  // These values are inspected directly in tests, but maybe not necessary to keep around
98
98
  this.keepAlive = typeof options.keepAlive === 'boolean' ? options.keepAlive : true;
@@ -316,8 +316,7 @@ class Connection extends EventEmitter {
316
316
  if (typeof options === 'function') (callback = options), (options = {});
317
317
 
318
318
  const conn = this;
319
- const socketTimeout =
320
- typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
319
+ const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
321
320
  const bson = conn.options.bson;
322
321
  const query = new Query(bson, ns, command, {
323
322
  numberToSkip: 0,
@@ -63,8 +63,8 @@ var _id = 0;
63
63
  * @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
64
64
  * @param {boolean} [options.noDelay=true] TCP Connection no delay
65
65
  * @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
66
- * @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
67
- * @param {number} [options.monitoringSocketTimeout=30000] TCP Socket timeout setting for replicaset monitoring socket
66
+ * @param {number} [options.socketTimeout=0] TCP Socket timeout setting
67
+ * @param {number} [options.monitoringSocketTimeout=0] TCP Socket timeout setting for replicaset monitoring socket
68
68
  * @param {boolean} [options.ssl=false] Use SSL for connection
69
69
  * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
70
70
  * @param {Buffer} [options.ca] SSL Certificate store binary buffer
@@ -111,7 +111,7 @@ var Pool = function(topology, options) {
111
111
  minSize: 0,
112
112
  // socket settings
113
113
  connectionTimeout: 30000,
114
- socketTimeout: 360000,
114
+ socketTimeout: 0,
115
115
  keepAlive: true,
116
116
  keepAliveInitialDelay: 120000,
117
117
  noDelay: true,
@@ -250,6 +250,7 @@ class TopologyDescription {
250
250
  if (descriptionsWithError.length > 0) {
251
251
  return descriptionsWithError[0].error;
252
252
  }
253
+ return undefined;
253
254
  }
254
255
 
255
256
  /**
@@ -919,7 +919,7 @@ ReplSet.prototype.connect = function(options) {
919
919
  );
920
920
  });
921
921
 
922
- // Error out as high availbility interval must be < than socketTimeout
922
+ // Error out as high availability interval must be < than socketTimeout
923
923
  if (
924
924
  this.s.options.socketTimeout > 0 &&
925
925
  this.s.options.socketTimeout <= this.s.options.haInterval
@@ -75,7 +75,7 @@ function topologyId(server) {
75
75
  * @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
76
76
  * @param {boolean} [options.noDelay=true] TCP Connection no delay
77
77
  * @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
78
- * @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
78
+ * @param {number} [options.socketTimeout=0] TCP Socket timeout setting
79
79
  * @param {boolean} [options.ssl=false] Use SSL for connection
80
80
  * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
81
81
  * @param {Buffer} [options.ca] SSL Certificate store binary buffer
@@ -389,7 +389,7 @@ var eventHandler = function(self, event) {
389
389
  event === 'timeout' ||
390
390
  event === 'reconnect' ||
391
391
  event === 'attemptReconnect' ||
392
- 'reconnectFailed'
392
+ event === 'reconnectFailed'
393
393
  ) {
394
394
  // Remove server instance from accounting
395
395
  if (
@@ -687,15 +687,6 @@ function parseConnectionString(uri, options, callback) {
687
687
  return callback(new MongoParseError('directConnection option requires exactly one host'));
688
688
  }
689
689
 
690
- // NOTE: this behavior will go away in v4.0, we will always auto discover there
691
- if (
692
- parsedOptions.directConnection == null &&
693
- hosts.length === 1 &&
694
- parsedOptions.replicaSet == null
695
- ) {
696
- parsedOptions.directConnection = true;
697
- }
698
-
699
690
  const result = {
700
691
  hosts: hosts,
701
692
  auth: auth.db || auth.username ? auth : null,
@@ -153,6 +153,7 @@ var GridStore = function GridStore(db, id, filename, mode, options) {
153
153
  },
154
154
  set: function(value) {
155
155
  if (!(this.mode[0] === 'w' && this.position === 0 && this.uploadDate == null)) {
156
+ // eslint-disable-next-line no-self-assign
156
157
  this.internalChunkSize = this.internalChunkSize;
157
158
  } else {
158
159
  this.internalChunkSize = value;
@@ -97,7 +97,7 @@ const validOptions = require('./operations/connect').validOptions;
97
97
  * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
98
98
  * @param {number} [options.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
99
99
  * @param {number} [options.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
100
- * @param {number} [options.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
100
+ * @param {number} [options.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
101
101
  * @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
102
102
  * If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
103
103
  * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
@@ -169,6 +169,7 @@ function MongoClient(url, options) {
169
169
  dbCache: new Map(),
170
170
  sessions: new Set(),
171
171
  writeConcern: WriteConcern.fromOptions(options),
172
+ readPreference: ReadPreference.fromOptions(options) || ReadPreference.primary,
172
173
  namespace: new MongoDBNamespace('admin')
173
174
  };
174
175
  }
@@ -188,7 +189,7 @@ Object.defineProperty(MongoClient.prototype, 'writeConcern', {
188
189
  Object.defineProperty(MongoClient.prototype, 'readPreference', {
189
190
  enumerable: true,
190
191
  get: function() {
191
- return ReadPreference.primary;
192
+ return this.s.readPreference;
192
193
  }
193
194
  });
194
195
 
@@ -371,7 +372,7 @@ MongoClient.prototype.isConnected = function(options) {
371
372
  * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
372
373
  * @param {number} [options.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
373
374
  * @param {number} [options.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
374
- * @param {number} [options.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
375
+ * @param {number} [options.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
375
376
  * @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
376
377
  * If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
377
378
  * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
@@ -22,7 +22,9 @@ class AddUserOperation extends CommandOperation {
22
22
  const options = this.options;
23
23
 
24
24
  // Get additional values
25
- let roles = Array.isArray(options.roles) ? options.roles : [];
25
+ let roles = [];
26
+ if (Array.isArray(options.roles)) roles = options.roles;
27
+ if (typeof options.roles === 'string') roles = [options.roles];
26
28
 
27
29
  // If not roles defined print deprecated message
28
30
  // TODO: handle deprecation properly
@@ -39,7 +39,7 @@ function validateCollection(admin, collectionName, options, callback) {
39
39
 
40
40
  // Decorate command with extra options
41
41
  for (let i = 0; i < keys.length; i++) {
42
- if (options.hasOwnProperty(keys[i]) && keys[i] !== 'session') {
42
+ if (Object.prototype.hasOwnProperty.call(options, keys[i]) && keys[i] !== 'session') {
43
43
  command[keys[i]] = options[keys[i]];
44
44
  }
45
45
  }
@@ -17,7 +17,9 @@ class CommandOperationV2 extends OperationBase {
17
17
 
18
18
  this.ns = parent.s.namespace.withCollection('$cmd');
19
19
  const propertyProvider = this.hasAspect(Aspect.NO_INHERIT_OPTIONS) ? undefined : parent;
20
- this.readPreference = ReadPreference.resolve(propertyProvider, this.options);
20
+ this.readPreference = this.hasAspect(Aspect.WRITE_OPERATION)
21
+ ? ReadPreference.primary
22
+ : ReadPreference.resolve(propertyProvider, this.options);
21
23
  this.readConcern = resolveReadConcern(propertyProvider, this.options);
22
24
  this.writeConcern = resolveWriteConcern(propertyProvider, this.options);
23
25
  this.explain = false;
@@ -290,7 +290,7 @@ function connect(mongoClient, url, options, callback) {
290
290
  const _finalOptions = createUnifiedOptions(object, options);
291
291
 
292
292
  // Check if we have connection and socket timeout set
293
- if (_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 360000;
293
+ if (_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 0;
294
294
  if (_finalOptions.connectTimeoutMS == null) _finalOptions.connectTimeoutMS = 10000;
295
295
  if (_finalOptions.retryWrites == null) _finalOptions.retryWrites = true;
296
296
  if (_finalOptions.useRecoveryToken == null) _finalOptions.useRecoveryToken = true;
@@ -788,7 +788,7 @@ function translateOptions(options, translationOptions) {
788
788
  }
789
789
 
790
790
  // Set the socket and connection timeouts
791
- if (options.socketTimeoutMS == null) options.socketTimeoutMS = 360000;
791
+ if (options.socketTimeoutMS == null) options.socketTimeoutMS = 0;
792
792
  if (options.connectTimeoutMS == null) options.connectTimeoutMS = 10000;
793
793
 
794
794
  if (!translationOptions.createServers) {
@@ -8,7 +8,7 @@ class ValidateCollectionOperation extends CommandOperation {
8
8
  let command = { validate: collectionName };
9
9
  const keys = Object.keys(options);
10
10
  for (let i = 0; i < keys.length; i++) {
11
- if (options.hasOwnProperty(keys[i]) && keys[i] !== 'session') {
11
+ if (Object.prototype.hasOwnProperty.call(options, keys[i]) && keys[i] !== 'session') {
12
12
  command[keys[i]] = options[keys[i]];
13
13
  }
14
14
  }
@@ -84,7 +84,7 @@ var legalOptionNames = [
84
84
  * @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
85
85
  * @param {number} [options.socketOptions.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
86
86
  * @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
87
- * @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
87
+ * @param {number} [options.socketOptions.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
88
88
  * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
89
89
  * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
90
90
  * @fires Mongos#connect
@@ -86,7 +86,7 @@ var legalOptionNames = [
86
86
  * @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
87
87
  * @param {number} [options.socketOptions.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
88
88
  * @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
89
- * @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
89
+ * @param {number} [options.socketOptions.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
90
90
  * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
91
91
  * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
92
92
  * @param {boolean} [options.monitoring=true] Triggers the server instance to call ismaster
package/lib/utils.js CHANGED
@@ -565,7 +565,10 @@ function deprecateOptions(config, fn) {
565
565
  }
566
566
 
567
567
  config.deprecatedOptions.forEach(deprecatedOption => {
568
- if (options.hasOwnProperty(deprecatedOption) && !optionsWarned.has(deprecatedOption)) {
568
+ if (
569
+ Object.prototype.hasOwnProperty.call(options, deprecatedOption) &&
570
+ !optionsWarned.has(deprecatedOption)
571
+ ) {
569
572
  optionsWarned.add(deprecatedOption);
570
573
  const msg = msgHandler(config.name, deprecatedOption);
571
574
  emitDeprecationWarning(msg);
@@ -713,12 +716,13 @@ function makeInterruptableAsyncInterval(fn, options) {
713
716
  const interval = options.interval || 1000;
714
717
  const minInterval = options.minInterval || 500;
715
718
  const immediate = typeof options.immediate === 'boolean' ? options.immediate : false;
719
+ const clock = typeof options.clock === 'function' ? options.clock : now;
716
720
 
717
721
  function wake() {
718
- const currentTime = now();
722
+ const currentTime = clock();
719
723
  const timeSinceLastWake = currentTime - lastWakeTime;
720
724
  const timeSinceLastCall = currentTime - lastCallTime;
721
- const timeUntilNextCall = Math.max(interval - timeSinceLastCall, 0);
725
+ const timeUntilNextCall = interval - timeSinceLastCall;
722
726
  lastWakeTime = currentTime;
723
727
 
724
728
  // For the streaming protocol: there is nothing obviously stopping this
@@ -737,6 +741,14 @@ function makeInterruptableAsyncInterval(fn, options) {
737
741
  if (timeUntilNextCall > minInterval) {
738
742
  reschedule(minInterval);
739
743
  }
744
+
745
+ // This is possible in virtualized environments like AWS Lambda where our
746
+ // clock is unreliable. In these cases the timer is "running" but never
747
+ // actually completes, so we want to execute immediately and then attempt
748
+ // to reschedule.
749
+ if (timeUntilNextCall < 0) {
750
+ executeAndReschedule();
751
+ }
740
752
  }
741
753
 
742
754
  function stop() {
@@ -758,7 +770,7 @@ function makeInterruptableAsyncInterval(fn, options) {
758
770
 
759
771
  function executeAndReschedule() {
760
772
  lastWakeTime = 0;
761
- lastCallTime = now();
773
+ lastCallTime = clock();
762
774
 
763
775
  fn(err => {
764
776
  if (err) throw err;
@@ -769,7 +781,7 @@ function makeInterruptableAsyncInterval(fn, options) {
769
781
  if (immediate) {
770
782
  executeAndReschedule();
771
783
  } else {
772
- lastCallTime = now();
784
+ lastCallTime = clock();
773
785
  reschedule();
774
786
  }
775
787
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mongodb",
3
- "version": "3.6.2",
3
+ "version": "3.6.3",
4
4
  "description": "The official MongoDB driver for Node.js",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -23,6 +23,26 @@
23
23
  "snappy": "^6.3.4",
24
24
  "bson-ext": "^2.0.0"
25
25
  },
26
+ "peerDependenciesMeta": {
27
+ "kerberos": {
28
+ "optional": true
29
+ },
30
+ "mongodb-client-encryption": {
31
+ "optional": true
32
+ },
33
+ "mongodb-extjson": {
34
+ "optional": true
35
+ },
36
+ "snappy": {
37
+ "optional": true
38
+ },
39
+ "bson-ext": {
40
+ "optional": true
41
+ },
42
+ "aws4": {
43
+ "optional": true
44
+ }
45
+ },
26
46
  "dependencies": {
27
47
  "bl": "^2.2.1",
28
48
  "bson": "^1.1.4",
@@ -36,8 +56,10 @@
36
56
  "chalk": "^2.4.2",
37
57
  "co": "4.6.0",
38
58
  "coveralls": "^2.11.6",
39
- "eslint": "^4.5.0",
40
- "eslint-plugin-prettier": "^2.2.0",
59
+ "eslint": "^7.10.0",
60
+ "eslint-config-prettier": "^6.11.0",
61
+ "eslint-plugin-es": "^3.0.1",
62
+ "eslint-plugin-prettier": "^3.1.3",
41
63
  "istanbul": "^0.4.5",
42
64
  "jsdoc": "3.5.5",
43
65
  "lodash.camelcase": "^4.3.0",
@@ -68,11 +90,11 @@
68
90
  "check:kerberos": "mocha --opts '{}' -t 60000 test/manual/kerberos.test.js",
69
91
  "check:ldap": "mocha --opts '{}' test/manual/ldap.test.js",
70
92
  "check:tls": "mocha --opts '{}' test/manual/tls_support.test.js",
71
- "test": "npm run lint && mocha --recursive test/functional test/unit test/core",
72
- "test-nolint": "mocha --recursive test/functional test/unit test/core",
73
- "coverage": "istanbul cover mongodb-test-runner -- -t 60000 test/core test/unit test/functional",
93
+ "test": "npm run lint && mocha --recursive test/functional test/unit",
94
+ "test-nolint": "mocha --recursive test/functional test/unit",
95
+ "coverage": "istanbul cover mongodb-test-runner -- -t 60000 test/unit test/functional",
74
96
  "lint": "eslint -v && eslint lib test",
75
- "format": "prettier --print-width 100 --tab-width 2 --single-quote --write 'test/**/*.js' 'lib/**/*.js'",
97
+ "format": "npm run lint -- --fix",
76
98
  "bench": "node test/benchmarks/driverBench/",
77
99
  "generate-evergreen": "node .evergreen/generate_evergreen_tasks.js",
78
100
  "release": "standard-version -i HISTORY.md"