mongodb 4.4.1 → 4.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 (204) hide show
  1. package/README.md +3 -2
  2. package/lib/admin.js +5 -6
  3. package/lib/admin.js.map +1 -1
  4. package/lib/bulk/common.js +34 -7
  5. package/lib/bulk/common.js.map +1 -1
  6. package/lib/bulk/unordered.js.map +1 -1
  7. package/lib/change_stream.js +251 -245
  8. package/lib/change_stream.js.map +1 -1
  9. package/lib/cmap/auth/gssapi.js.map +1 -1
  10. package/lib/cmap/auth/mongocr.js.map +1 -1
  11. package/lib/cmap/auth/mongodb_aws.js +3 -0
  12. package/lib/cmap/auth/mongodb_aws.js.map +1 -1
  13. package/lib/cmap/auth/plain.js.map +1 -1
  14. package/lib/cmap/auth/scram.js +1 -0
  15. package/lib/cmap/auth/scram.js.map +1 -1
  16. package/lib/cmap/auth/x509.js.map +1 -1
  17. package/lib/cmap/commands.js +12 -11
  18. package/lib/cmap/commands.js.map +1 -1
  19. package/lib/cmap/connect.js +8 -1
  20. package/lib/cmap/connect.js.map +1 -1
  21. package/lib/cmap/connection.js +111 -145
  22. package/lib/cmap/connection.js.map +1 -1
  23. package/lib/cmap/errors.js.map +1 -1
  24. package/lib/cmap/message_stream.js.map +1 -1
  25. package/lib/cmap/stream_description.js +3 -0
  26. package/lib/cmap/stream_description.js.map +1 -1
  27. package/lib/collection.js +60 -29
  28. package/lib/collection.js.map +1 -1
  29. package/lib/connection_string.js +32 -11
  30. package/lib/connection_string.js.map +1 -1
  31. package/lib/constants.js +8 -1
  32. package/lib/constants.js.map +1 -1
  33. package/lib/cursor/abstract_cursor.js +64 -51
  34. package/lib/cursor/abstract_cursor.js.map +1 -1
  35. package/lib/cursor/aggregation_cursor.js +2 -2
  36. package/lib/cursor/aggregation_cursor.js.map +1 -1
  37. package/lib/cursor/find_cursor.js +9 -4
  38. package/lib/cursor/find_cursor.js.map +1 -1
  39. package/lib/db.js +20 -13
  40. package/lib/db.js.map +1 -1
  41. package/lib/encrypter.js +21 -10
  42. package/lib/encrypter.js.map +1 -1
  43. package/lib/error.js +121 -59
  44. package/lib/error.js.map +1 -1
  45. package/lib/gridfs/download.js +2 -0
  46. package/lib/gridfs/download.js.map +1 -1
  47. package/lib/gridfs/index.js +42 -51
  48. package/lib/gridfs/index.js.map +1 -1
  49. package/lib/gridfs/upload.js +1 -1
  50. package/lib/gridfs/upload.js.map +1 -1
  51. package/lib/index.js +7 -3
  52. package/lib/index.js.map +1 -1
  53. package/lib/mongo_client.js +21 -27
  54. package/lib/mongo_client.js.map +1 -1
  55. package/lib/operations/add_user.js +8 -1
  56. package/lib/operations/add_user.js.map +1 -1
  57. package/lib/operations/aggregate.js +5 -0
  58. package/lib/operations/aggregate.js.map +1 -1
  59. package/lib/operations/bulk_write.js.map +1 -1
  60. package/lib/operations/collections.js.map +1 -1
  61. package/lib/operations/command.js +0 -3
  62. package/lib/operations/command.js.map +1 -1
  63. package/lib/operations/common_functions.js +8 -1
  64. package/lib/operations/common_functions.js.map +1 -1
  65. package/lib/operations/count.js.map +1 -1
  66. package/lib/operations/count_documents.js.map +1 -1
  67. package/lib/operations/create_collection.js +51 -17
  68. package/lib/operations/create_collection.js.map +1 -1
  69. package/lib/operations/delete.js +5 -3
  70. package/lib/operations/delete.js.map +1 -1
  71. package/lib/operations/distinct.js.map +1 -1
  72. package/lib/operations/drop.js +67 -7
  73. package/lib/operations/drop.js.map +1 -1
  74. package/lib/operations/estimated_document_count.js.map +1 -1
  75. package/lib/operations/eval.js.map +1 -1
  76. package/lib/operations/execute_operation.js +71 -79
  77. package/lib/operations/execute_operation.js.map +1 -1
  78. package/lib/operations/find.js +3 -52
  79. package/lib/operations/find.js.map +1 -1
  80. package/lib/operations/find_and_modify.js +5 -0
  81. package/lib/operations/find_and_modify.js.map +1 -1
  82. package/lib/operations/get_more.js +5 -0
  83. package/lib/operations/get_more.js.map +1 -1
  84. package/lib/operations/indexes.js +8 -9
  85. package/lib/operations/indexes.js.map +1 -1
  86. package/lib/operations/insert.js +8 -2
  87. package/lib/operations/insert.js.map +1 -1
  88. package/lib/operations/is_capped.js.map +1 -1
  89. package/lib/operations/list_collections.js +10 -42
  90. package/lib/operations/list_collections.js.map +1 -1
  91. package/lib/operations/list_databases.js +5 -0
  92. package/lib/operations/list_databases.js.map +1 -1
  93. package/lib/operations/map_reduce.js +1 -2
  94. package/lib/operations/map_reduce.js.map +1 -1
  95. package/lib/operations/operation.js +1 -3
  96. package/lib/operations/operation.js.map +1 -1
  97. package/lib/operations/options_operation.js.map +1 -1
  98. package/lib/operations/profiling_level.js.map +1 -1
  99. package/lib/operations/remove_user.js.map +1 -1
  100. package/lib/operations/rename.js +1 -1
  101. package/lib/operations/rename.js.map +1 -1
  102. package/lib/operations/run_command.js.map +1 -1
  103. package/lib/operations/set_profiling_level.js.map +1 -1
  104. package/lib/operations/stats.js.map +1 -1
  105. package/lib/operations/update.js +5 -0
  106. package/lib/operations/update.js.map +1 -1
  107. package/lib/operations/validate_collection.js.map +1 -1
  108. package/lib/read_concern.js +1 -0
  109. package/lib/read_concern.js.map +1 -1
  110. package/lib/sdam/common.js +1 -7
  111. package/lib/sdam/common.js.map +1 -1
  112. package/lib/sdam/events.js +1 -1
  113. package/lib/sdam/events.js.map +1 -1
  114. package/lib/sdam/monitor.js +1 -2
  115. package/lib/sdam/monitor.js.map +1 -1
  116. package/lib/sdam/server.js +108 -78
  117. package/lib/sdam/server.js.map +1 -1
  118. package/lib/sdam/topology.js +38 -55
  119. package/lib/sdam/topology.js.map +1 -1
  120. package/lib/sdam/topology_description.js +3 -4
  121. package/lib/sdam/topology_description.js.map +1 -1
  122. package/lib/sessions.js +93 -68
  123. package/lib/sessions.js.map +1 -1
  124. package/lib/utils.js +21 -97
  125. package/lib/utils.js.map +1 -1
  126. package/mongodb.d.ts +417 -92
  127. package/package.json +25 -29
  128. package/src/admin.ts +6 -10
  129. package/src/bulk/common.ts +45 -14
  130. package/src/bulk/unordered.ts +1 -1
  131. package/src/change_stream.ts +559 -425
  132. package/src/cmap/auth/gssapi.ts +1 -1
  133. package/src/cmap/auth/mongocr.ts +1 -1
  134. package/src/cmap/auth/mongodb_aws.ts +6 -1
  135. package/src/cmap/auth/plain.ts +1 -1
  136. package/src/cmap/auth/scram.ts +3 -2
  137. package/src/cmap/auth/x509.ts +6 -2
  138. package/src/cmap/commands.ts +26 -22
  139. package/src/cmap/connect.ts +15 -14
  140. package/src/cmap/connection.ts +163 -185
  141. package/src/cmap/errors.ts +2 -2
  142. package/src/cmap/message_stream.ts +2 -2
  143. package/src/cmap/stream_description.ts +4 -1
  144. package/src/collection.ts +66 -35
  145. package/src/connection_string.ts +46 -18
  146. package/src/constants.ts +6 -0
  147. package/src/cursor/abstract_cursor.ts +87 -65
  148. package/src/cursor/aggregation_cursor.ts +4 -4
  149. package/src/cursor/find_cursor.ts +16 -8
  150. package/src/db.ts +27 -24
  151. package/src/deps.ts +40 -0
  152. package/src/encrypter.ts +22 -11
  153. package/src/error.ts +170 -89
  154. package/src/gridfs/download.ts +3 -1
  155. package/src/gridfs/index.ts +51 -68
  156. package/src/gridfs/upload.ts +13 -13
  157. package/src/index.ts +21 -0
  158. package/src/mongo_client.ts +36 -50
  159. package/src/mongo_types.ts +1 -1
  160. package/src/operations/add_user.ts +14 -3
  161. package/src/operations/aggregate.ts +15 -5
  162. package/src/operations/bulk_write.ts +6 -2
  163. package/src/operations/collections.ts +6 -2
  164. package/src/operations/command.ts +23 -12
  165. package/src/operations/common_functions.ts +8 -1
  166. package/src/operations/count.ts +6 -2
  167. package/src/operations/count_documents.ts +5 -1
  168. package/src/operations/create_collection.ts +91 -23
  169. package/src/operations/delete.ts +19 -13
  170. package/src/operations/distinct.ts +6 -2
  171. package/src/operations/drop.ts +100 -10
  172. package/src/operations/estimated_document_count.ts +11 -3
  173. package/src/operations/eval.ts +6 -2
  174. package/src/operations/execute_operation.ts +103 -101
  175. package/src/operations/find.ts +9 -85
  176. package/src/operations/find_and_modify.ts +21 -2
  177. package/src/operations/get_more.ts +20 -6
  178. package/src/operations/indexes.ts +54 -36
  179. package/src/operations/insert.ts +28 -7
  180. package/src/operations/is_capped.ts +6 -2
  181. package/src/operations/list_collections.ts +24 -59
  182. package/src/operations/list_databases.ts +13 -3
  183. package/src/operations/map_reduce.ts +7 -6
  184. package/src/operations/operation.ts +10 -9
  185. package/src/operations/options_operation.ts +6 -2
  186. package/src/operations/profiling_level.ts +6 -2
  187. package/src/operations/remove_user.ts +6 -2
  188. package/src/operations/rename.ts +7 -3
  189. package/src/operations/run_command.ts +6 -2
  190. package/src/operations/set_profiling_level.ts +6 -2
  191. package/src/operations/stats.ts +12 -4
  192. package/src/operations/update.ts +19 -9
  193. package/src/operations/validate_collection.ts +6 -2
  194. package/src/read_concern.ts +1 -0
  195. package/src/sdam/common.ts +0 -6
  196. package/src/sdam/events.ts +2 -2
  197. package/src/sdam/monitor.ts +4 -5
  198. package/src/sdam/server.ts +125 -117
  199. package/src/sdam/topology.ts +39 -78
  200. package/src/sdam/topology_description.ts +3 -4
  201. package/src/sessions.ts +108 -78
  202. package/src/utils.ts +39 -119
  203. package/tsconfig.json +40 -0
  204. package/mongodb.ts34.d.ts +0 -5720
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ChangeStreamCursor = exports.ChangeStream = void 0;
4
4
  const Denque = require("denque");
5
5
  const collection_1 = require("./collection");
6
+ const constants_1 = require("./constants");
6
7
  const abstract_cursor_1 = require("./cursor/abstract_cursor");
7
8
  const db_1 = require("./db");
8
9
  const error_1 = require("./error");
@@ -19,13 +20,27 @@ const kCursorStream = Symbol('cursorStream');
19
20
  const kClosed = Symbol('closed');
20
21
  /** @internal */
21
22
  const kMode = Symbol('mode');
22
- const CHANGE_STREAM_OPTIONS = ['resumeAfter', 'startAfter', 'startAtOperationTime', 'fullDocument'];
23
- const CURSOR_OPTIONS = ['batchSize', 'maxAwaitTimeMS', 'collation', 'readPreference'].concat(CHANGE_STREAM_OPTIONS);
23
+ const CHANGE_STREAM_OPTIONS = [
24
+ 'resumeAfter',
25
+ 'startAfter',
26
+ 'startAtOperationTime',
27
+ 'fullDocument'
28
+ ];
29
+ const CURSOR_OPTIONS = [
30
+ 'batchSize',
31
+ 'maxAwaitTimeMS',
32
+ 'collation',
33
+ 'readPreference',
34
+ 'comment',
35
+ ...CHANGE_STREAM_OPTIONS
36
+ ];
24
37
  const CHANGE_DOMAIN_TYPES = {
25
38
  COLLECTION: Symbol('Collection'),
26
39
  DATABASE: Symbol('Database'),
27
40
  CLUSTER: Symbol('Cluster')
28
41
  };
42
+ const SELECTION_TIMEOUT = 30000;
43
+ const CHANGE_STREAM_EVENTS = [constants_1.RESUME_TOKEN_CHANGED, constants_1.END, constants_1.CLOSE];
29
44
  const NO_RESUME_TOKEN_ERROR = 'A change stream document has been received that lacks a resume token (_id).';
30
45
  const NO_CURSOR_ERROR = 'ChangeStream has no cursor';
31
46
  const CHANGESTREAM_CLOSED_ERROR = 'ChangeStream is closed';
@@ -63,13 +78,13 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
63
78
  }
64
79
  this[kResumeQueue] = new Denque();
65
80
  // Create contained Change Stream cursor
66
- this.cursor = createChangeStreamCursor(this, options);
81
+ this.cursor = this._createChangeStreamCursor(options);
67
82
  this[kClosed] = false;
68
83
  this[kMode] = false;
69
84
  // Listen for any `change` listeners being added to ChangeStream
70
85
  this.on('newListener', eventName => {
71
86
  if (eventName === 'change' && this.cursor && this.listenerCount('change') === 0) {
72
- streamEvents(this, this.cursor);
87
+ this._streamEvents(this.cursor);
73
88
  }
74
89
  });
75
90
  this.on('removeListener', eventName => {
@@ -89,9 +104,9 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
89
104
  return (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.resumeToken;
90
105
  }
91
106
  hasNext(callback) {
92
- setIsIterator(this);
107
+ this._setIsIterator();
93
108
  return (0, utils_1.maybePromise)(callback, cb => {
94
- getCursor(this, (err, cursor) => {
109
+ this._getCursor((err, cursor) => {
95
110
  if (err || !cursor)
96
111
  return cb(err); // failed to resume, raise an error
97
112
  cursor.hasNext(cb);
@@ -99,18 +114,18 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
99
114
  });
100
115
  }
101
116
  next(callback) {
102
- setIsIterator(this);
117
+ this._setIsIterator();
103
118
  return (0, utils_1.maybePromise)(callback, cb => {
104
- getCursor(this, (err, cursor) => {
119
+ this._getCursor((err, cursor) => {
105
120
  if (err || !cursor)
106
121
  return cb(err); // failed to resume, raise an error
107
122
  cursor.next((error, change) => {
108
123
  if (error) {
109
124
  this[kResumeQueue].push(() => this.next(cb));
110
- processError(this, error, cb);
125
+ this._processError(error, cb);
111
126
  return;
112
127
  }
113
- processNewChange(this, change, cb);
128
+ this._processNewChange(change !== null && change !== void 0 ? change : null, cb);
114
129
  });
115
130
  });
116
131
  });
@@ -129,7 +144,7 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
129
144
  }
130
145
  const cursor = this.cursor;
131
146
  return cursor.close(err => {
132
- endStream(this);
147
+ this._endStream();
133
148
  this.cursor = undefined;
134
149
  return cb(err);
135
150
  });
@@ -146,41 +161,243 @@ class ChangeStream extends mongo_types_1.TypedEventEmitter {
146
161
  return this.cursor.stream(options);
147
162
  }
148
163
  tryNext(callback) {
149
- setIsIterator(this);
164
+ this._setIsIterator();
150
165
  return (0, utils_1.maybePromise)(callback, cb => {
151
- getCursor(this, (err, cursor) => {
166
+ this._getCursor((err, cursor) => {
152
167
  if (err || !cursor)
153
168
  return cb(err); // failed to resume, raise an error
154
169
  return cursor.tryNext(cb);
155
170
  });
156
171
  });
157
172
  }
173
+ /** @internal */
174
+ _setIsEmitter() {
175
+ if (this[kMode] === 'iterator') {
176
+ // TODO(NODE-3485): Replace with MongoChangeStreamModeError
177
+ throw new error_1.MongoAPIError('ChangeStream cannot be used as an EventEmitter after being used as an iterator');
178
+ }
179
+ this[kMode] = 'emitter';
180
+ }
181
+ /** @internal */
182
+ _setIsIterator() {
183
+ if (this[kMode] === 'emitter') {
184
+ // TODO(NODE-3485): Replace with MongoChangeStreamModeError
185
+ throw new error_1.MongoAPIError('ChangeStream cannot be used as an iterator after being used as an EventEmitter');
186
+ }
187
+ this[kMode] = 'iterator';
188
+ }
189
+ /**
190
+ * Create a new change stream cursor based on self's configuration
191
+ * @internal
192
+ */
193
+ _createChangeStreamCursor(options) {
194
+ const changeStreamStageOptions = (0, utils_1.filterOptions)(options, CHANGE_STREAM_OPTIONS);
195
+ if (this.type === CHANGE_DOMAIN_TYPES.CLUSTER) {
196
+ changeStreamStageOptions.allChangesForCluster = true;
197
+ }
198
+ const pipeline = [{ $changeStream: changeStreamStageOptions }, ...this.pipeline];
199
+ const cursorOptions = (0, utils_1.filterOptions)(options, CURSOR_OPTIONS);
200
+ const changeStreamCursor = new ChangeStreamCursor((0, utils_1.getTopology)(this.parent), this.namespace, pipeline, cursorOptions);
201
+ for (const event of CHANGE_STREAM_EVENTS) {
202
+ changeStreamCursor.on(event, e => this.emit(event, e));
203
+ }
204
+ if (this.listenerCount(ChangeStream.CHANGE) > 0) {
205
+ this._streamEvents(changeStreamCursor);
206
+ }
207
+ return changeStreamCursor;
208
+ }
209
+ /**
210
+ * This method performs a basic server selection loop, satisfying the requirements of
211
+ * ChangeStream resumability until the new SDAM layer can be used.
212
+ * @internal
213
+ */
214
+ _waitForTopologyConnected(topology, options, callback) {
215
+ setTimeout(() => {
216
+ if (options && options.start == null) {
217
+ options.start = (0, utils_1.now)();
218
+ }
219
+ const start = options.start || (0, utils_1.now)();
220
+ const timeout = options.timeout || SELECTION_TIMEOUT;
221
+ if (topology.isConnected()) {
222
+ return callback();
223
+ }
224
+ if ((0, utils_1.calculateDurationInMs)(start) > timeout) {
225
+ // TODO(NODE-3497): Replace with MongoNetworkTimeoutError
226
+ return callback(new error_1.MongoRuntimeError('Timed out waiting for connection'));
227
+ }
228
+ this._waitForTopologyConnected(topology, options, callback);
229
+ }, 500); // this is an arbitrary wait time to allow SDAM to transition
230
+ }
231
+ /** @internal */
232
+ _closeWithError(error, callback) {
233
+ if (!callback) {
234
+ this.emit(ChangeStream.ERROR, error);
235
+ }
236
+ this.close(() => callback && callback(error));
237
+ }
238
+ /** @internal */
239
+ _streamEvents(cursor) {
240
+ var _a;
241
+ this._setIsEmitter();
242
+ const stream = (_a = this[kCursorStream]) !== null && _a !== void 0 ? _a : cursor.stream();
243
+ this[kCursorStream] = stream;
244
+ stream.on('data', change => this._processNewChange(change));
245
+ stream.on('error', error => this._processError(error));
246
+ }
247
+ /** @internal */
248
+ _endStream() {
249
+ const cursorStream = this[kCursorStream];
250
+ if (cursorStream) {
251
+ ['data', 'close', 'end', 'error'].forEach(event => cursorStream.removeAllListeners(event));
252
+ cursorStream.destroy();
253
+ }
254
+ this[kCursorStream] = undefined;
255
+ }
256
+ /** @internal */
257
+ _processNewChange(change, callback) {
258
+ var _a;
259
+ if (this[kClosed]) {
260
+ // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
261
+ if (callback)
262
+ callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
263
+ return;
264
+ }
265
+ // a null change means the cursor has been notified, implicitly closing the change stream
266
+ if (change == null) {
267
+ // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
268
+ return this._closeWithError(new error_1.MongoRuntimeError(CHANGESTREAM_CLOSED_ERROR), callback);
269
+ }
270
+ if (change && !change._id) {
271
+ return this._closeWithError(new error_1.MongoChangeStreamError(NO_RESUME_TOKEN_ERROR), callback);
272
+ }
273
+ // cache the resume token
274
+ (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.cacheResumeToken(change._id);
275
+ // wipe the startAtOperationTime if there was one so that there won't be a conflict
276
+ // between resumeToken and startAtOperationTime if we need to reconnect the cursor
277
+ this.options.startAtOperationTime = undefined;
278
+ // Return the change
279
+ if (!callback)
280
+ return this.emit(ChangeStream.CHANGE, change);
281
+ return callback(undefined, change);
282
+ }
283
+ /** @internal */
284
+ _processError(error, callback) {
285
+ const cursor = this.cursor;
286
+ // If the change stream has been closed explicitly, do not process error.
287
+ if (this[kClosed]) {
288
+ // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
289
+ if (callback)
290
+ callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
291
+ return;
292
+ }
293
+ // if the resume succeeds, continue with the new cursor
294
+ const resumeWithCursor = (newCursor) => {
295
+ this.cursor = newCursor;
296
+ this._processResumeQueue();
297
+ };
298
+ // otherwise, raise an error and close the change stream
299
+ const unresumableError = (err) => {
300
+ if (!callback) {
301
+ this.emit(ChangeStream.ERROR, err);
302
+ }
303
+ this.close(() => this._processResumeQueue(err));
304
+ };
305
+ if (cursor && (0, error_1.isResumableError)(error, (0, utils_1.maxWireVersion)(cursor.server))) {
306
+ this.cursor = undefined;
307
+ // stop listening to all events from old cursor
308
+ this._endStream();
309
+ // close internal cursor, ignore errors
310
+ cursor.close();
311
+ const topology = (0, utils_1.getTopology)(this.parent);
312
+ this._waitForTopologyConnected(topology, { readPreference: cursor.readPreference }, err => {
313
+ // if the topology can't reconnect, close the stream
314
+ if (err)
315
+ return unresumableError(err);
316
+ // create a new cursor, preserving the old cursor's options
317
+ const newCursor = this._createChangeStreamCursor(cursor.resumeOptions);
318
+ // attempt to continue in emitter mode
319
+ if (!callback)
320
+ return resumeWithCursor(newCursor);
321
+ // attempt to continue in iterator mode
322
+ newCursor.hasNext(err => {
323
+ // if there's an error immediately after resuming, close the stream
324
+ if (err)
325
+ return unresumableError(err);
326
+ resumeWithCursor(newCursor);
327
+ });
328
+ });
329
+ return;
330
+ }
331
+ // if initial error wasn't resumable, raise an error and close the change stream
332
+ return this._closeWithError(error, callback);
333
+ }
334
+ /** @internal */
335
+ _getCursor(callback) {
336
+ if (this[kClosed]) {
337
+ // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
338
+ callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
339
+ return;
340
+ }
341
+ // if a cursor exists and it is open, return it
342
+ if (this.cursor) {
343
+ callback(undefined, this.cursor);
344
+ return;
345
+ }
346
+ // no cursor, queue callback until topology reconnects
347
+ this[kResumeQueue].push(callback);
348
+ }
349
+ /**
350
+ * Drain the resume queue when a new has become available
351
+ * @internal
352
+ *
353
+ * @param err - error getting a new cursor
354
+ */
355
+ _processResumeQueue(error) {
356
+ var _a;
357
+ while (this[kResumeQueue].length) {
358
+ const request = this[kResumeQueue].pop();
359
+ if (!request)
360
+ break; // Should never occur but TS can't use the length check in the while condition
361
+ if (!error) {
362
+ if (this[kClosed]) {
363
+ // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
364
+ request(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
365
+ return;
366
+ }
367
+ if (!this.cursor) {
368
+ request(new error_1.MongoChangeStreamError(NO_CURSOR_ERROR));
369
+ return;
370
+ }
371
+ }
372
+ request(error, (_a = this.cursor) !== null && _a !== void 0 ? _a : undefined);
373
+ }
374
+ }
158
375
  }
159
376
  exports.ChangeStream = ChangeStream;
160
377
  /** @event */
161
- ChangeStream.RESPONSE = 'response';
378
+ ChangeStream.RESPONSE = constants_1.RESPONSE;
162
379
  /** @event */
163
- ChangeStream.MORE = 'more';
380
+ ChangeStream.MORE = constants_1.MORE;
164
381
  /** @event */
165
- ChangeStream.INIT = 'init';
382
+ ChangeStream.INIT = constants_1.INIT;
166
383
  /** @event */
167
- ChangeStream.CLOSE = 'close';
384
+ ChangeStream.CLOSE = constants_1.CLOSE;
168
385
  /**
169
386
  * Fired for each new matching change in the specified namespace. Attaching a `change`
170
387
  * event listener to a Change Stream will switch the stream into flowing mode. Data will
171
388
  * then be passed as soon as it is available.
172
389
  * @event
173
390
  */
174
- ChangeStream.CHANGE = 'change';
391
+ ChangeStream.CHANGE = constants_1.CHANGE;
175
392
  /** @event */
176
- ChangeStream.END = 'end';
393
+ ChangeStream.END = constants_1.END;
177
394
  /** @event */
178
- ChangeStream.ERROR = 'error';
395
+ ChangeStream.ERROR = constants_1.ERROR;
179
396
  /**
180
397
  * Emitted each time the change stream stores a new resume token.
181
398
  * @event
182
399
  */
183
- ChangeStream.RESUME_TOKEN_CHANGED = 'resumeTokenChanged';
400
+ ChangeStream.RESUME_TOKEN_CHANGED = constants_1.RESUME_TOKEN_CHANGED;
184
401
  /** @internal */
185
402
  class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
186
403
  constructor(topology, namespace, pipeline = [], options = {}) {
@@ -204,17 +421,14 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
204
421
  return this._resumeToken;
205
422
  }
206
423
  get resumeOptions() {
207
- const result = {};
208
- for (const optionName of CURSOR_OPTIONS) {
209
- if (Reflect.has(this.options, optionName)) {
210
- Reflect.set(result, optionName, Reflect.get(this.options, optionName));
211
- }
212
- }
424
+ const result = (0, utils_1.filterOptions)(this.options, CURSOR_OPTIONS);
213
425
  if (this.resumeToken || this.startAtOperationTime) {
214
- ['resumeAfter', 'startAfter', 'startAtOperationTime'].forEach(key => Reflect.deleteProperty(result, key));
426
+ for (const key of ['resumeAfter', 'startAfter', 'startAtOperationTime']) {
427
+ Reflect.deleteProperty(result, key);
428
+ }
215
429
  if (this.resumeToken) {
216
430
  const resumeKey = this.options.startAfter && !this.hasReceived ? 'startAfter' : 'resumeAfter';
217
- Reflect.set(result, resumeKey, this.resumeToken);
431
+ result[resumeKey] = this.resumeToken;
218
432
  }
219
433
  else if (this.startAtOperationTime && (0, utils_1.maxWireVersion)(this.server) >= 7) {
220
434
  result.startAtOperationTime = this.startAtOperationTime;
@@ -231,11 +445,12 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
231
445
  }
232
446
  this.hasReceived = true;
233
447
  }
234
- _processBatch(batchName, response) {
235
- const cursor = (response === null || response === void 0 ? void 0 : response.cursor) || {};
448
+ _processBatch(response) {
449
+ const cursor = response.cursor;
236
450
  if (cursor.postBatchResumeToken) {
237
- this.postBatchResumeToken = cursor.postBatchResumeToken;
238
- if (cursor[batchName].length === 0) {
451
+ this.postBatchResumeToken = response.cursor.postBatchResumeToken;
452
+ const batch = 'firstBatch' in response.cursor ? response.cursor.firstBatch : response.cursor.nextBatch;
453
+ if (batch.length === 0) {
239
454
  this.resumeToken = cursor.postBatchResumeToken;
240
455
  }
241
456
  }
@@ -251,7 +466,7 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
251
466
  ...this.options,
252
467
  session
253
468
  });
254
- (0, execute_operation_1.executeOperation)(this.topology, aggregateOperation, (err, response) => {
469
+ (0, execute_operation_1.executeOperation)(session, aggregateOperation, (err, response) => {
255
470
  if (err || response == null) {
256
471
  return callback(err);
257
472
  }
@@ -262,7 +477,7 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
262
477
  (0, utils_1.maxWireVersion)(server) >= 7) {
263
478
  this.startAtOperationTime = response.operationTime;
264
479
  }
265
- this._processBatch('firstBatch', response);
480
+ this._processBatch(response);
266
481
  this.emit(ChangeStream.INIT, response);
267
482
  this.emit(ChangeStream.RESPONSE);
268
483
  // TODO: NODE-2882
@@ -274,7 +489,7 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
274
489
  if (err) {
275
490
  return callback(err);
276
491
  }
277
- this._processBatch('nextBatch', response);
492
+ this._processBatch(response);
278
493
  this.emit(ChangeStream.MORE, response);
279
494
  this.emit(ChangeStream.RESPONSE);
280
495
  callback(err, response);
@@ -282,213 +497,4 @@ class ChangeStreamCursor extends abstract_cursor_1.AbstractCursor {
282
497
  }
283
498
  }
284
499
  exports.ChangeStreamCursor = ChangeStreamCursor;
285
- const CHANGE_STREAM_EVENTS = [
286
- ChangeStream.RESUME_TOKEN_CHANGED,
287
- ChangeStream.END,
288
- ChangeStream.CLOSE
289
- ];
290
- function setIsEmitter(changeStream) {
291
- if (changeStream[kMode] === 'iterator') {
292
- // TODO(NODE-3485): Replace with MongoChangeStreamModeError
293
- throw new error_1.MongoAPIError('ChangeStream cannot be used as an EventEmitter after being used as an iterator');
294
- }
295
- changeStream[kMode] = 'emitter';
296
- }
297
- function setIsIterator(changeStream) {
298
- if (changeStream[kMode] === 'emitter') {
299
- // TODO(NODE-3485): Replace with MongoChangeStreamModeError
300
- throw new error_1.MongoAPIError('ChangeStream cannot be used as an iterator after being used as an EventEmitter');
301
- }
302
- changeStream[kMode] = 'iterator';
303
- }
304
- /**
305
- * Create a new change stream cursor based on self's configuration
306
- * @internal
307
- */
308
- function createChangeStreamCursor(changeStream, options) {
309
- const changeStreamStageOptions = { fullDocument: options.fullDocument || 'default' };
310
- applyKnownOptions(changeStreamStageOptions, options, CHANGE_STREAM_OPTIONS);
311
- if (changeStream.type === CHANGE_DOMAIN_TYPES.CLUSTER) {
312
- changeStreamStageOptions.allChangesForCluster = true;
313
- }
314
- const pipeline = [{ $changeStream: changeStreamStageOptions }].concat(changeStream.pipeline);
315
- const cursorOptions = applyKnownOptions({}, options, CURSOR_OPTIONS);
316
- const changeStreamCursor = new ChangeStreamCursor((0, utils_1.getTopology)(changeStream.parent), changeStream.namespace, pipeline, cursorOptions);
317
- for (const event of CHANGE_STREAM_EVENTS) {
318
- changeStreamCursor.on(event, e => changeStream.emit(event, e));
319
- }
320
- if (changeStream.listenerCount(ChangeStream.CHANGE) > 0) {
321
- streamEvents(changeStream, changeStreamCursor);
322
- }
323
- return changeStreamCursor;
324
- }
325
- function applyKnownOptions(target, source, optionNames) {
326
- optionNames.forEach(name => {
327
- if (source[name]) {
328
- target[name] = source[name];
329
- }
330
- });
331
- return target;
332
- }
333
- // This method performs a basic server selection loop, satisfying the requirements of
334
- // ChangeStream resumability until the new SDAM layer can be used.
335
- const SELECTION_TIMEOUT = 30000;
336
- function waitForTopologyConnected(topology, options, callback) {
337
- setTimeout(() => {
338
- if (options && options.start == null) {
339
- options.start = (0, utils_1.now)();
340
- }
341
- const start = options.start || (0, utils_1.now)();
342
- const timeout = options.timeout || SELECTION_TIMEOUT;
343
- if (topology.isConnected()) {
344
- return callback();
345
- }
346
- if ((0, utils_1.calculateDurationInMs)(start) > timeout) {
347
- // TODO(NODE-3497): Replace with MongoNetworkTimeoutError
348
- return callback(new error_1.MongoRuntimeError('Timed out waiting for connection'));
349
- }
350
- waitForTopologyConnected(topology, options, callback);
351
- }, 500); // this is an arbitrary wait time to allow SDAM to transition
352
- }
353
- function closeWithError(changeStream, error, callback) {
354
- if (!callback) {
355
- changeStream.emit(ChangeStream.ERROR, error);
356
- }
357
- changeStream.close(() => callback && callback(error));
358
- }
359
- function streamEvents(changeStream, cursor) {
360
- setIsEmitter(changeStream);
361
- const stream = changeStream[kCursorStream] || cursor.stream();
362
- changeStream[kCursorStream] = stream;
363
- stream.on('data', change => processNewChange(changeStream, change));
364
- stream.on('error', error => processError(changeStream, error));
365
- }
366
- function endStream(changeStream) {
367
- const cursorStream = changeStream[kCursorStream];
368
- if (cursorStream) {
369
- ['data', 'close', 'end', 'error'].forEach(event => cursorStream.removeAllListeners(event));
370
- cursorStream.destroy();
371
- }
372
- changeStream[kCursorStream] = undefined;
373
- }
374
- function processNewChange(changeStream, change, callback) {
375
- var _a;
376
- if (changeStream[kClosed]) {
377
- // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
378
- if (callback)
379
- callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
380
- return;
381
- }
382
- // a null change means the cursor has been notified, implicitly closing the change stream
383
- if (change == null) {
384
- // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
385
- return closeWithError(changeStream, new error_1.MongoRuntimeError(CHANGESTREAM_CLOSED_ERROR), callback);
386
- }
387
- if (change && !change._id) {
388
- return closeWithError(changeStream, new error_1.MongoChangeStreamError(NO_RESUME_TOKEN_ERROR), callback);
389
- }
390
- // cache the resume token
391
- (_a = changeStream.cursor) === null || _a === void 0 ? void 0 : _a.cacheResumeToken(change._id);
392
- // wipe the startAtOperationTime if there was one so that there won't be a conflict
393
- // between resumeToken and startAtOperationTime if we need to reconnect the cursor
394
- changeStream.options.startAtOperationTime = undefined;
395
- // Return the change
396
- if (!callback)
397
- return changeStream.emit(ChangeStream.CHANGE, change);
398
- return callback(undefined, change);
399
- }
400
- function processError(changeStream, error, callback) {
401
- const cursor = changeStream.cursor;
402
- // If the change stream has been closed explicitly, do not process error.
403
- if (changeStream[kClosed]) {
404
- // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
405
- if (callback)
406
- callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
407
- return;
408
- }
409
- // if the resume succeeds, continue with the new cursor
410
- function resumeWithCursor(newCursor) {
411
- changeStream.cursor = newCursor;
412
- processResumeQueue(changeStream);
413
- }
414
- // otherwise, raise an error and close the change stream
415
- function unresumableError(err) {
416
- if (!callback) {
417
- changeStream.emit(ChangeStream.ERROR, err);
418
- }
419
- changeStream.close(() => processResumeQueue(changeStream, err));
420
- }
421
- if (cursor && (0, error_1.isResumableError)(error, (0, utils_1.maxWireVersion)(cursor.server))) {
422
- changeStream.cursor = undefined;
423
- // stop listening to all events from old cursor
424
- endStream(changeStream);
425
- // close internal cursor, ignore errors
426
- cursor.close();
427
- const topology = (0, utils_1.getTopology)(changeStream.parent);
428
- waitForTopologyConnected(topology, { readPreference: cursor.readPreference }, err => {
429
- // if the topology can't reconnect, close the stream
430
- if (err)
431
- return unresumableError(err);
432
- // create a new cursor, preserving the old cursor's options
433
- const newCursor = createChangeStreamCursor(changeStream, cursor.resumeOptions);
434
- // attempt to continue in emitter mode
435
- if (!callback)
436
- return resumeWithCursor(newCursor);
437
- // attempt to continue in iterator mode
438
- newCursor.hasNext(err => {
439
- // if there's an error immediately after resuming, close the stream
440
- if (err)
441
- return unresumableError(err);
442
- resumeWithCursor(newCursor);
443
- });
444
- });
445
- return;
446
- }
447
- // if initial error wasn't resumable, raise an error and close the change stream
448
- return closeWithError(changeStream, error, callback);
449
- }
450
- /**
451
- * Safely provides a cursor across resume attempts
452
- *
453
- * @param changeStream - the parent ChangeStream
454
- */
455
- function getCursor(changeStream, callback) {
456
- if (changeStream[kClosed]) {
457
- // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
458
- callback(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
459
- return;
460
- }
461
- // if a cursor exists and it is open, return it
462
- if (changeStream.cursor) {
463
- callback(undefined, changeStream.cursor);
464
- return;
465
- }
466
- // no cursor, queue callback until topology reconnects
467
- changeStream[kResumeQueue].push(callback);
468
- }
469
- /**
470
- * Drain the resume queue when a new has become available
471
- *
472
- * @param changeStream - the parent ChangeStream
473
- * @param err - error getting a new cursor
474
- */
475
- function processResumeQueue(changeStream, err) {
476
- while (changeStream[kResumeQueue].length) {
477
- const request = changeStream[kResumeQueue].pop();
478
- if (!request)
479
- break; // Should never occur but TS can't use the length check in the while condition
480
- if (!err) {
481
- if (changeStream[kClosed]) {
482
- // TODO(NODE-3485): Replace with MongoChangeStreamClosedError
483
- request(new error_1.MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
484
- return;
485
- }
486
- if (!changeStream.cursor) {
487
- request(new error_1.MongoChangeStreamError(NO_CURSOR_ERROR));
488
- return;
489
- }
490
- }
491
- request(err, changeStream.cursor);
492
- }
493
- }
494
500
  //# sourceMappingURL=change_stream.js.map