mongodb 6.9.0 → 6.10.0-dev.20241024.sha.5c4355ad
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/lib/beta.d.ts +411 -16
- package/lib/bson.js +1 -0
- package/lib/bson.js.map +1 -1
- package/lib/bulk/common.js +60 -71
- package/lib/bulk/common.js.map +1 -1
- package/lib/bulk/unordered.js +3 -3
- package/lib/bulk/unordered.js.map +1 -1
- package/lib/change_stream.js +3 -2
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +5 -8
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js +1 -1
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/command_builders.js +1 -1
- package/lib/cmap/auth/mongodb_oidc/command_builders.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/human_callback_workflow.js +1 -1
- package/lib/cmap/auth/mongodb_oidc/human_callback_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/machine_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +10 -1
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/commands.js +50 -18
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connection.js +9 -2
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/wire_protocol/constants.js +2 -2
- package/lib/cmap/wire_protocol/on_demand/document.js.map +1 -1
- package/lib/cmap/wire_protocol/responses.js +26 -1
- package/lib/cmap/wire_protocol/responses.js.map +1 -1
- package/lib/connection_string.js +1 -7
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/client_bulk_write_cursor.js +52 -0
- package/lib/cursor/client_bulk_write_cursor.js.map +1 -0
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/db.js +1 -1
- package/lib/error.js +83 -10
- package/lib/error.js.map +1 -1
- package/lib/explain.js +6 -6
- package/lib/explain.js.map +1 -1
- package/lib/index.js +6 -3
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +14 -0
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_client_auth_providers.js +6 -2
- package/lib/mongo_client_auth_providers.js.map +1 -1
- package/lib/mongo_types.js.map +1 -1
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/client_bulk_write/client_bulk_write.js +83 -0
- package/lib/operations/client_bulk_write/client_bulk_write.js.map +1 -0
- package/lib/operations/client_bulk_write/command_builder.js +154 -19
- package/lib/operations/client_bulk_write/command_builder.js.map +1 -1
- package/lib/operations/client_bulk_write/executor.js +109 -0
- package/lib/operations/client_bulk_write/executor.js.map +1 -0
- package/lib/operations/client_bulk_write/results_merger.js +204 -0
- package/lib/operations/client_bulk_write/results_merger.js.map +1 -0
- package/lib/operations/execute_operation.js +7 -0
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/operation.js +5 -1
- package/lib/operations/operation.js.map +1 -1
- package/lib/operations/search_indexes/create.js.map +1 -1
- package/lib/operations/search_indexes/drop.js.map +1 -1
- package/lib/operations/search_indexes/update.js.map +1 -1
- package/lib/read_concern.js +1 -1
- package/lib/sdam/server.js +2 -1
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +5 -2
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/server_selection.js +5 -2
- package/lib/sdam/server_selection.js.map +1 -1
- package/lib/sdam/srv_polling.js +5 -1
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +9 -2
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +30 -11
- package/lib/utils.js.map +1 -1
- package/lib/write_concern.js.map +1 -1
- package/mongodb.d.ts +411 -16
- package/package.json +2 -2
- package/src/beta.ts +1 -1
- package/src/bson.ts +3 -0
- package/src/bulk/common.ts +80 -120
- package/src/bulk/unordered.ts +3 -4
- package/src/change_stream.ts +5 -2
- package/src/cmap/auth/mongo_credentials.ts +5 -9
- package/src/cmap/auth/mongodb_aws.ts +1 -1
- package/src/cmap/auth/mongodb_oidc/callback_workflow.ts +1 -1
- package/src/cmap/auth/mongodb_oidc/command_builders.ts +1 -2
- package/src/cmap/auth/mongodb_oidc/human_callback_workflow.ts +1 -2
- package/src/cmap/auth/mongodb_oidc/machine_workflow.ts +1 -1
- package/src/cmap/auth/mongodb_oidc.ts +1 -2
- package/src/cmap/command_monitoring_events.ts +16 -2
- package/src/cmap/commands.ts +71 -25
- package/src/cmap/connection.ts +17 -4
- package/src/cmap/handshake/client_metadata.ts +1 -1
- package/src/cmap/wire_protocol/constants.ts +2 -2
- package/src/cmap/wire_protocol/on_demand/document.ts +1 -2
- package/src/cmap/wire_protocol/responses.ts +31 -2
- package/src/connection_string.ts +2 -9
- package/src/cursor/aggregation_cursor.ts +2 -2
- package/src/cursor/client_bulk_write_cursor.ts +79 -0
- package/src/cursor/find_cursor.ts +2 -2
- package/src/db.ts +1 -1
- package/src/error.ts +105 -9
- package/src/explain.ts +47 -11
- package/src/index.ts +26 -1
- package/src/mongo_client.ts +30 -2
- package/src/mongo_client_auth_providers.ts +8 -2
- package/src/mongo_types.ts +2 -1
- package/src/operations/aggregate.ts +9 -1
- package/src/operations/client_bulk_write/client_bulk_write.ts +107 -0
- package/src/operations/client_bulk_write/command_builder.ts +216 -30
- package/src/operations/client_bulk_write/common.ts +148 -23
- package/src/operations/client_bulk_write/executor.ts +137 -0
- package/src/operations/client_bulk_write/results_merger.ts +260 -0
- package/src/operations/execute_operation.ts +8 -0
- package/src/operations/find.ts +8 -1
- package/src/operations/operation.ts +6 -1
- package/src/operations/search_indexes/create.ts +1 -2
- package/src/operations/search_indexes/drop.ts +1 -2
- package/src/operations/search_indexes/update.ts +1 -2
- package/src/read_concern.ts +1 -1
- package/src/sdam/server.ts +2 -1
- package/src/sdam/server_description.ts +11 -2
- package/src/sdam/server_selection.ts +5 -2
- package/src/sdam/srv_polling.ts +5 -2
- package/src/sdam/topology_description.ts +0 -1
- package/src/sessions.ts +16 -2
- package/src/utils.ts +45 -12
- package/src/write_concern.ts +4 -1
- package/lib/cmap/auth/mongocr.js +0 -35
- package/lib/cmap/auth/mongocr.js.map +0 -1
- package/src/cmap/auth/mongocr.ts +0 -38
package/src/bulk/common.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { promisify } from 'util';
|
|
2
|
-
|
|
3
1
|
import { type BSONSerializeOptions, type Document, EJSON, resolveBSONOptions } from '../bson';
|
|
4
2
|
import type { Collection } from '../collection';
|
|
5
3
|
import {
|
|
@@ -7,6 +5,7 @@ import {
|
|
|
7
5
|
MongoBatchReExecutionError,
|
|
8
6
|
MONGODB_ERROR_CODES,
|
|
9
7
|
MongoInvalidArgumentError,
|
|
8
|
+
MongoRuntimeError,
|
|
10
9
|
MongoServerError,
|
|
11
10
|
MongoWriteConcernError
|
|
12
11
|
} from '../error';
|
|
@@ -22,7 +21,6 @@ import type { Topology } from '../sdam/topology';
|
|
|
22
21
|
import type { ClientSession } from '../sessions';
|
|
23
22
|
import {
|
|
24
23
|
applyRetryableWrites,
|
|
25
|
-
type Callback,
|
|
26
24
|
getTopology,
|
|
27
25
|
hasAtomicOperators,
|
|
28
26
|
maybeAddIdToDocuments,
|
|
@@ -500,86 +498,46 @@ export function mergeBatchResults(
|
|
|
500
498
|
}
|
|
501
499
|
}
|
|
502
500
|
|
|
503
|
-
function executeCommands(
|
|
501
|
+
async function executeCommands(
|
|
504
502
|
bulkOperation: BulkOperationBase,
|
|
505
|
-
options: BulkWriteOptions
|
|
506
|
-
|
|
507
|
-
) {
|
|
503
|
+
options: BulkWriteOptions
|
|
504
|
+
): Promise<BulkWriteResult> {
|
|
508
505
|
if (bulkOperation.s.batches.length === 0) {
|
|
509
|
-
return
|
|
510
|
-
undefined,
|
|
511
|
-
new BulkWriteResult(bulkOperation.s.bulkResult, bulkOperation.isOrdered)
|
|
512
|
-
);
|
|
506
|
+
return new BulkWriteResult(bulkOperation.s.bulkResult, bulkOperation.isOrdered);
|
|
513
507
|
}
|
|
514
508
|
|
|
515
|
-
const batch
|
|
509
|
+
for (const batch of bulkOperation.s.batches) {
|
|
510
|
+
const finalOptions = resolveOptions(bulkOperation, {
|
|
511
|
+
...options,
|
|
512
|
+
ordered: bulkOperation.isOrdered
|
|
513
|
+
});
|
|
516
514
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (err && 'message' in err && !(err instanceof MongoWriteConcernError)) {
|
|
520
|
-
return callback(
|
|
521
|
-
new MongoBulkWriteError(
|
|
522
|
-
err,
|
|
523
|
-
new BulkWriteResult(bulkOperation.s.bulkResult, bulkOperation.isOrdered)
|
|
524
|
-
)
|
|
525
|
-
);
|
|
515
|
+
if (finalOptions.bypassDocumentValidation !== true) {
|
|
516
|
+
delete finalOptions.bypassDocumentValidation;
|
|
526
517
|
}
|
|
527
518
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
bulkOperation.s.bulkResult,
|
|
532
|
-
bulkOperation.isOrdered,
|
|
533
|
-
err,
|
|
534
|
-
callback
|
|
535
|
-
);
|
|
519
|
+
// Is the bypassDocumentValidation options specific
|
|
520
|
+
if (bulkOperation.s.bypassDocumentValidation === true) {
|
|
521
|
+
finalOptions.bypassDocumentValidation = true;
|
|
536
522
|
}
|
|
537
523
|
|
|
538
|
-
//
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
if (bulkOperation.handleWriteError(callback, writeResult)) return;
|
|
542
|
-
|
|
543
|
-
// Execute the next command in line
|
|
544
|
-
executeCommands(bulkOperation, options, callback);
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
const finalOptions = resolveOptions(bulkOperation, {
|
|
548
|
-
...options,
|
|
549
|
-
ordered: bulkOperation.isOrdered
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
if (finalOptions.bypassDocumentValidation !== true) {
|
|
553
|
-
delete finalOptions.bypassDocumentValidation;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// Set an operationIf if provided
|
|
557
|
-
if (bulkOperation.operationId) {
|
|
558
|
-
resultHandler.operationId = bulkOperation.operationId;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
// Is the bypassDocumentValidation options specific
|
|
562
|
-
if (bulkOperation.s.bypassDocumentValidation === true) {
|
|
563
|
-
finalOptions.bypassDocumentValidation = true;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// Is the checkKeys option disabled
|
|
567
|
-
if (bulkOperation.s.checkKeys === false) {
|
|
568
|
-
finalOptions.checkKeys = false;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
if (finalOptions.retryWrites) {
|
|
572
|
-
if (isUpdateBatch(batch)) {
|
|
573
|
-
finalOptions.retryWrites = finalOptions.retryWrites && !batch.operations.some(op => op.multi);
|
|
524
|
+
// Is the checkKeys option disabled
|
|
525
|
+
if (bulkOperation.s.checkKeys === false) {
|
|
526
|
+
finalOptions.checkKeys = false;
|
|
574
527
|
}
|
|
575
528
|
|
|
576
|
-
if (
|
|
577
|
-
|
|
578
|
-
finalOptions.retryWrites
|
|
529
|
+
if (finalOptions.retryWrites) {
|
|
530
|
+
if (isUpdateBatch(batch)) {
|
|
531
|
+
finalOptions.retryWrites =
|
|
532
|
+
finalOptions.retryWrites && !batch.operations.some(op => op.multi);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (isDeleteBatch(batch)) {
|
|
536
|
+
finalOptions.retryWrites =
|
|
537
|
+
finalOptions.retryWrites && !batch.operations.some(op => op.limit === 0);
|
|
538
|
+
}
|
|
579
539
|
}
|
|
580
|
-
}
|
|
581
540
|
|
|
582
|
-
try {
|
|
583
541
|
const operation = isInsertBatch(batch)
|
|
584
542
|
? new InsertOperation(bulkOperation.s.namespace, batch.operations, finalOptions)
|
|
585
543
|
: isUpdateBatch(batch)
|
|
@@ -588,39 +546,50 @@ function executeCommands(
|
|
|
588
546
|
? new DeleteOperation(bulkOperation.s.namespace, batch.operations, finalOptions)
|
|
589
547
|
: null;
|
|
590
548
|
|
|
591
|
-
if (operation
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
549
|
+
if (operation == null) throw new MongoRuntimeError(`Unknown batchType: ${batch.batchType}`);
|
|
550
|
+
|
|
551
|
+
let thrownError = null;
|
|
552
|
+
let result;
|
|
553
|
+
try {
|
|
554
|
+
result = await executeOperation(bulkOperation.s.collection.client, operation);
|
|
555
|
+
} catch (error) {
|
|
556
|
+
thrownError = error;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (thrownError != null) {
|
|
560
|
+
if (thrownError instanceof MongoWriteConcernError) {
|
|
561
|
+
mergeBatchResults(batch, bulkOperation.s.bulkResult, thrownError, result);
|
|
562
|
+
const writeResult = new BulkWriteResult(
|
|
563
|
+
bulkOperation.s.bulkResult,
|
|
564
|
+
bulkOperation.isOrdered
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
throw new MongoBulkWriteError(
|
|
568
|
+
{
|
|
569
|
+
message: thrownError.result.writeConcernError.errmsg,
|
|
570
|
+
code: thrownError.result.writeConcernError.code
|
|
571
|
+
},
|
|
572
|
+
writeResult
|
|
573
|
+
);
|
|
574
|
+
} else {
|
|
575
|
+
// Error is a driver related error not a bulk op error, return early
|
|
576
|
+
throw new MongoBulkWriteError(
|
|
577
|
+
thrownError,
|
|
578
|
+
new BulkWriteResult(bulkOperation.s.bulkResult, bulkOperation.isOrdered)
|
|
579
|
+
);
|
|
580
|
+
}
|
|
596
581
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
mergeBatchResults(batch, bulkOperation.s.bulkResult, err, undefined);
|
|
602
|
-
callback();
|
|
582
|
+
|
|
583
|
+
mergeBatchResults(batch, bulkOperation.s.bulkResult, thrownError, result);
|
|
584
|
+
const writeResult = new BulkWriteResult(bulkOperation.s.bulkResult, bulkOperation.isOrdered);
|
|
585
|
+
bulkOperation.handleWriteError(writeResult);
|
|
603
586
|
}
|
|
604
|
-
}
|
|
605
587
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
bulkResult
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
callback: Callback<BulkWriteResult>
|
|
612
|
-
) {
|
|
613
|
-
mergeBatchResults(batch, bulkResult, undefined, err.result);
|
|
614
|
-
|
|
615
|
-
callback(
|
|
616
|
-
new MongoBulkWriteError(
|
|
617
|
-
{
|
|
618
|
-
message: err.result.writeConcernError.errmsg,
|
|
619
|
-
code: err.result.writeConcernError.code
|
|
620
|
-
},
|
|
621
|
-
new BulkWriteResult(bulkResult, isOrdered)
|
|
622
|
-
)
|
|
623
|
-
);
|
|
588
|
+
bulkOperation.s.batches.length = 0;
|
|
589
|
+
|
|
590
|
+
const writeResult = new BulkWriteResult(bulkOperation.s.bulkResult, bulkOperation.isOrdered);
|
|
591
|
+
bulkOperation.handleWriteError(writeResult);
|
|
592
|
+
return writeResult;
|
|
624
593
|
}
|
|
625
594
|
|
|
626
595
|
/**
|
|
@@ -875,8 +844,6 @@ export interface BulkWriteOptions extends CommandOperationOptions {
|
|
|
875
844
|
let?: Document;
|
|
876
845
|
}
|
|
877
846
|
|
|
878
|
-
const executeCommandsAsync = promisify(executeCommands);
|
|
879
|
-
|
|
880
847
|
/**
|
|
881
848
|
* TODO(NODE-4063)
|
|
882
849
|
* BulkWrites merge complexity is implemented in executeCommands
|
|
@@ -895,7 +862,7 @@ export class BulkWriteShimOperation extends AbstractOperation {
|
|
|
895
862
|
return 'bulkWrite' as const;
|
|
896
863
|
}
|
|
897
864
|
|
|
898
|
-
execute(_server: Server, session: ClientSession | undefined): Promise<any> {
|
|
865
|
+
async execute(_server: Server, session: ClientSession | undefined): Promise<any> {
|
|
899
866
|
if (this.options.session == null) {
|
|
900
867
|
// An implicit session could have been created by 'executeOperation'
|
|
901
868
|
// So if we stick it on finalOptions here, each bulk operation
|
|
@@ -903,7 +870,7 @@ export class BulkWriteShimOperation extends AbstractOperation {
|
|
|
903
870
|
// an explicit session would be
|
|
904
871
|
this.options.session = session;
|
|
905
872
|
}
|
|
906
|
-
return
|
|
873
|
+
return await executeCommands(this.bulkOperation, this.options);
|
|
907
874
|
}
|
|
908
875
|
}
|
|
909
876
|
|
|
@@ -1239,33 +1206,26 @@ export abstract class BulkOperationBase {
|
|
|
1239
1206
|
* Handles the write error before executing commands
|
|
1240
1207
|
* @internal
|
|
1241
1208
|
*/
|
|
1242
|
-
handleWriteError(
|
|
1209
|
+
handleWriteError(writeResult: BulkWriteResult): void {
|
|
1243
1210
|
if (this.s.bulkResult.writeErrors.length > 0) {
|
|
1244
1211
|
const msg = this.s.bulkResult.writeErrors[0].errmsg
|
|
1245
1212
|
? this.s.bulkResult.writeErrors[0].errmsg
|
|
1246
1213
|
: 'write operation failed';
|
|
1247
1214
|
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
writeResult
|
|
1256
|
-
)
|
|
1215
|
+
throw new MongoBulkWriteError(
|
|
1216
|
+
{
|
|
1217
|
+
message: msg,
|
|
1218
|
+
code: this.s.bulkResult.writeErrors[0].code,
|
|
1219
|
+
writeErrors: this.s.bulkResult.writeErrors
|
|
1220
|
+
},
|
|
1221
|
+
writeResult
|
|
1257
1222
|
);
|
|
1258
|
-
|
|
1259
|
-
return true;
|
|
1260
1223
|
}
|
|
1261
1224
|
|
|
1262
1225
|
const writeConcernError = writeResult.getWriteConcernError();
|
|
1263
1226
|
if (writeConcernError) {
|
|
1264
|
-
|
|
1265
|
-
return true;
|
|
1227
|
+
throw new MongoBulkWriteError(writeConcernError, writeResult);
|
|
1266
1228
|
}
|
|
1267
|
-
|
|
1268
|
-
return false;
|
|
1269
1229
|
}
|
|
1270
1230
|
|
|
1271
1231
|
abstract addToOperationsList(
|
package/src/bulk/unordered.ts
CHANGED
|
@@ -4,7 +4,6 @@ import type { Collection } from '../collection';
|
|
|
4
4
|
import { MongoInvalidArgumentError } from '../error';
|
|
5
5
|
import type { DeleteStatement } from '../operations/delete';
|
|
6
6
|
import type { UpdateStatement } from '../operations/update';
|
|
7
|
-
import { type Callback } from '../utils';
|
|
8
7
|
import {
|
|
9
8
|
Batch,
|
|
10
9
|
BatchType,
|
|
@@ -20,12 +19,12 @@ export class UnorderedBulkOperation extends BulkOperationBase {
|
|
|
20
19
|
super(collection, options, false);
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
override handleWriteError(
|
|
22
|
+
override handleWriteError(writeResult: BulkWriteResult): void {
|
|
24
23
|
if (this.s.batches.length) {
|
|
25
|
-
return
|
|
24
|
+
return;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
return super.handleWriteError(
|
|
27
|
+
return super.handleWriteError(writeResult);
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
addToOperationsList(
|
package/src/change_stream.ts
CHANGED
|
@@ -946,7 +946,7 @@ export class ChangeStream<
|
|
|
946
946
|
// If the change stream has been closed explicitly, do not process error.
|
|
947
947
|
if (this[kClosed]) return;
|
|
948
948
|
|
|
949
|
-
if (isResumableError(changeStreamError, this.cursor.maxWireVersion)) {
|
|
949
|
+
if (this.cursor.id != null && isResumableError(changeStreamError, this.cursor.maxWireVersion)) {
|
|
950
950
|
this._endStream();
|
|
951
951
|
|
|
952
952
|
this.cursor.close().then(undefined, squashError);
|
|
@@ -975,7 +975,10 @@ export class ChangeStream<
|
|
|
975
975
|
throw new MongoAPIError(CHANGESTREAM_CLOSED_ERROR);
|
|
976
976
|
}
|
|
977
977
|
|
|
978
|
-
if (
|
|
978
|
+
if (
|
|
979
|
+
this.cursor.id == null ||
|
|
980
|
+
!isResumableError(changeStreamError, this.cursor.maxWireVersion)
|
|
981
|
+
) {
|
|
979
982
|
try {
|
|
980
983
|
await this.close();
|
|
981
984
|
} catch (error) {
|
|
@@ -10,7 +10,9 @@ import { GSSAPICanonicalizationValue } from './gssapi';
|
|
|
10
10
|
import type { OIDCCallbackFunction } from './mongodb_oidc';
|
|
11
11
|
import { AUTH_MECHS_AUTH_SRC_EXTERNAL, AuthMechanism } from './providers';
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* @see https://github.com/mongodb/specifications/blob/master/source/auth/auth.md
|
|
15
|
+
*/
|
|
14
16
|
function getDefaultAuthMechanism(hello: Document | null): AuthMechanism {
|
|
15
17
|
if (hello) {
|
|
16
18
|
// If hello contains saslSupportedMechs, use scram-sha-256
|
|
@@ -20,15 +22,10 @@ function getDefaultAuthMechanism(hello: Document | null): AuthMechanism {
|
|
|
20
22
|
? AuthMechanism.MONGODB_SCRAM_SHA256
|
|
21
23
|
: AuthMechanism.MONGODB_SCRAM_SHA1;
|
|
22
24
|
}
|
|
23
|
-
|
|
24
|
-
// Fallback to legacy selection method. If wire version >= 3, use scram-sha-1
|
|
25
|
-
if (hello.maxWireVersion >= 3) {
|
|
26
|
-
return AuthMechanism.MONGODB_SCRAM_SHA1;
|
|
27
|
-
}
|
|
28
25
|
}
|
|
29
26
|
|
|
30
|
-
// Default for
|
|
31
|
-
return AuthMechanism.
|
|
27
|
+
// Default auth mechanism for 4.0 and higher.
|
|
28
|
+
return AuthMechanism.MONGODB_SCRAM_SHA256;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
const ALLOWED_ENVIRONMENT_NAMES: AuthMechanismProperties['ENVIRONMENT'][] = [
|
|
@@ -173,7 +170,6 @@ export class MongoCredentials {
|
|
|
173
170
|
validate(): void {
|
|
174
171
|
if (
|
|
175
172
|
(this.mechanism === AuthMechanism.MONGODB_GSSAPI ||
|
|
176
|
-
this.mechanism === AuthMechanism.MONGODB_CR ||
|
|
177
173
|
this.mechanism === AuthMechanism.MONGODB_PLAIN ||
|
|
178
174
|
this.mechanism === AuthMechanism.MONGODB_SCRAM_SHA1 ||
|
|
179
175
|
this.mechanism === AuthMechanism.MONGODB_SCRAM_SHA256) &&
|
|
@@ -107,7 +107,7 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
107
107
|
|
|
108
108
|
if (!ByteUtils.equals(serverNonce.subarray(0, nonce.byteLength), nonce)) {
|
|
109
109
|
// throw because the serverNonce's leading 32 bytes must equal the client nonce's 32 bytes
|
|
110
|
-
// https://github.com/mongodb/specifications/blob/
|
|
110
|
+
// https://github.com/mongodb/specifications/blob/master/source/auth/auth.md#conversation-5
|
|
111
111
|
|
|
112
112
|
// TODO(NODE-3483)
|
|
113
113
|
throw new MongoRuntimeError('Server nonce does not begin with client nonce');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type Document } from 'bson';
|
|
2
1
|
import { setTimeout } from 'timers/promises';
|
|
3
2
|
|
|
3
|
+
import { type Document } from '../../../bson';
|
|
4
4
|
import { MongoMissingCredentialsError } from '../../../error';
|
|
5
5
|
import { ns } from '../../../utils';
|
|
6
6
|
import type { Connection } from '../../connection';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type Document } from 'bson';
|
|
2
1
|
import { setTimeout } from 'timers/promises';
|
|
3
2
|
|
|
3
|
+
import { type Document } from '../../../bson';
|
|
4
4
|
import { ns } from '../../../utils';
|
|
5
5
|
import type { Connection } from '../../connection';
|
|
6
6
|
import type { MongoCredentials } from '../mongo_credentials';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { Document } from 'bson';
|
|
2
|
-
|
|
1
|
+
import type { Document } from '../../bson';
|
|
3
2
|
import { MongoInvalidArgumentError, MongoMissingCredentialsError } from '../../error';
|
|
4
3
|
import type { HandshakeDocument } from '../connect';
|
|
5
4
|
import type { Connection } from '../connection';
|
|
@@ -7,7 +7,12 @@ import {
|
|
|
7
7
|
LEGACY_HELLO_COMMAND_CAMEL_CASE
|
|
8
8
|
} from '../constants';
|
|
9
9
|
import { calculateDurationInMs, deepCopy } from '../utils';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
DocumentSequence,
|
|
12
|
+
OpMsgRequest,
|
|
13
|
+
type OpQueryRequest,
|
|
14
|
+
type WriteProtocolMessageType
|
|
15
|
+
} from './commands';
|
|
11
16
|
import type { Connection } from './connection';
|
|
12
17
|
|
|
13
18
|
/**
|
|
@@ -249,7 +254,16 @@ const OP_QUERY_KEYS = [
|
|
|
249
254
|
/** Extract the actual command from the query, possibly up-converting if it's a legacy format */
|
|
250
255
|
function extractCommand(command: WriteProtocolMessageType): Document {
|
|
251
256
|
if (command instanceof OpMsgRequest) {
|
|
252
|
-
|
|
257
|
+
const cmd = deepCopy(command.command);
|
|
258
|
+
// For OP_MSG with payload type 1 we need to pull the documents
|
|
259
|
+
// array out of the document sequence for monitoring.
|
|
260
|
+
if (cmd.ops instanceof DocumentSequence) {
|
|
261
|
+
cmd.ops = cmd.ops.documents;
|
|
262
|
+
}
|
|
263
|
+
if (cmd.nsInfo instanceof DocumentSequence) {
|
|
264
|
+
cmd.nsInfo = cmd.nsInfo.documents;
|
|
265
|
+
}
|
|
266
|
+
return cmd;
|
|
253
267
|
}
|
|
254
268
|
|
|
255
269
|
if (command.query?.$query) {
|
package/src/cmap/commands.ts
CHANGED
|
@@ -74,6 +74,8 @@ export class OpQueryRequest {
|
|
|
74
74
|
awaitData: boolean;
|
|
75
75
|
exhaust: boolean;
|
|
76
76
|
partial: boolean;
|
|
77
|
+
/** moreToCome is an OP_MSG only concept */
|
|
78
|
+
moreToCome = false;
|
|
77
79
|
|
|
78
80
|
constructor(
|
|
79
81
|
public databaseName: string,
|
|
@@ -407,22 +409,80 @@ const OPTS_EXHAUST_ALLOWED = 1 << 16;
|
|
|
407
409
|
|
|
408
410
|
/** @internal */
|
|
409
411
|
export interface OpMsgOptions {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
412
|
+
socketTimeoutMS?: number;
|
|
413
|
+
session?: ClientSession;
|
|
414
|
+
numberToSkip?: number;
|
|
415
|
+
numberToReturn?: number;
|
|
416
|
+
returnFieldSelector?: Document;
|
|
417
|
+
pre32Limit?: number;
|
|
418
|
+
serializeFunctions?: boolean;
|
|
419
|
+
ignoreUndefined?: boolean;
|
|
420
|
+
maxBsonSize?: number;
|
|
421
|
+
checkKeys?: boolean;
|
|
422
|
+
secondaryOk?: boolean;
|
|
423
|
+
|
|
424
|
+
requestId?: number;
|
|
425
|
+
moreToCome?: boolean;
|
|
426
|
+
exhaustAllowed?: boolean;
|
|
417
427
|
readPreference: ReadPreference;
|
|
418
428
|
}
|
|
419
429
|
|
|
420
430
|
/** @internal */
|
|
421
431
|
export class DocumentSequence {
|
|
432
|
+
field: string;
|
|
422
433
|
documents: Document[];
|
|
434
|
+
serializedDocumentsLength: number;
|
|
435
|
+
private chunks: Uint8Array[];
|
|
436
|
+
private header: Buffer;
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Create a new document sequence for the provided field.
|
|
440
|
+
* @param field - The field it will replace.
|
|
441
|
+
*/
|
|
442
|
+
constructor(field: string, documents?: Document[]) {
|
|
443
|
+
this.field = field;
|
|
444
|
+
this.documents = [];
|
|
445
|
+
this.chunks = [];
|
|
446
|
+
this.serializedDocumentsLength = 0;
|
|
447
|
+
// Document sequences starts with type 1 at the first byte.
|
|
448
|
+
// Field strings must always be UTF-8.
|
|
449
|
+
const buffer = Buffer.allocUnsafe(1 + 4 + this.field.length + 1);
|
|
450
|
+
buffer[0] = 1;
|
|
451
|
+
// Third part is the field name at offset 5 with trailing null byte.
|
|
452
|
+
encodeUTF8Into(buffer, `${this.field}\0`, 5);
|
|
453
|
+
this.chunks.push(buffer);
|
|
454
|
+
this.header = buffer;
|
|
455
|
+
if (documents) {
|
|
456
|
+
for (const doc of documents) {
|
|
457
|
+
this.push(doc, BSON.serialize(doc));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
423
461
|
|
|
424
|
-
|
|
425
|
-
|
|
462
|
+
/**
|
|
463
|
+
* Push a document to the document sequence. Will serialize the document
|
|
464
|
+
* as well and return the current serialized length of all documents.
|
|
465
|
+
* @param document - The document to add.
|
|
466
|
+
* @param buffer - The serialized document in raw BSON.
|
|
467
|
+
* @returns The new total document sequence length.
|
|
468
|
+
*/
|
|
469
|
+
push(document: Document, buffer: Uint8Array): number {
|
|
470
|
+
this.serializedDocumentsLength += buffer.length;
|
|
471
|
+
// Push the document.
|
|
472
|
+
this.documents.push(document);
|
|
473
|
+
// Push the document raw bson.
|
|
474
|
+
this.chunks.push(buffer);
|
|
475
|
+
// Write the new length.
|
|
476
|
+
this.header?.writeInt32LE(4 + this.field.length + 1 + this.serializedDocumentsLength, 1);
|
|
477
|
+
return this.serializedDocumentsLength + this.header.length;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Get the fully serialized bytes for the document sequence section.
|
|
482
|
+
* @returns The section bytes.
|
|
483
|
+
*/
|
|
484
|
+
toBin(): Uint8Array {
|
|
485
|
+
return Buffer.concat(this.chunks);
|
|
426
486
|
}
|
|
427
487
|
}
|
|
428
488
|
|
|
@@ -465,7 +525,7 @@ export class OpMsgRequest {
|
|
|
465
525
|
|
|
466
526
|
// flags
|
|
467
527
|
this.checksumPresent = false;
|
|
468
|
-
this.moreToCome = options.moreToCome
|
|
528
|
+
this.moreToCome = options.moreToCome ?? command.writeConcern?.w === 0;
|
|
469
529
|
this.exhaustAllowed =
|
|
470
530
|
typeof options.exhaustAllowed === 'boolean' ? options.exhaustAllowed : false;
|
|
471
531
|
}
|
|
@@ -533,21 +593,7 @@ export class OpMsgRequest {
|
|
|
533
593
|
const chunks = [];
|
|
534
594
|
for (const [key, value] of Object.entries(document)) {
|
|
535
595
|
if (value instanceof DocumentSequence) {
|
|
536
|
-
|
|
537
|
-
const buffer = Buffer.allocUnsafe(1 + 4 + key.length);
|
|
538
|
-
buffer[0] = 1;
|
|
539
|
-
// Third part is the field name at offset 5.
|
|
540
|
-
encodeUTF8Into(buffer, key, 5);
|
|
541
|
-
chunks.push(buffer);
|
|
542
|
-
// Fourth part are the documents' bytes.
|
|
543
|
-
let docsLength = 0;
|
|
544
|
-
for (const doc of value.documents) {
|
|
545
|
-
const docBson = this.serializeBson(doc);
|
|
546
|
-
docsLength += docBson.length;
|
|
547
|
-
chunks.push(docBson);
|
|
548
|
-
}
|
|
549
|
-
// Second part of the sequence is the length at offset 1;
|
|
550
|
-
buffer.writeInt32LE(key.length + docsLength, 1);
|
|
596
|
+
chunks.push(value.toBin());
|
|
551
597
|
// Why are we removing the field from the command? This is because it needs to be
|
|
552
598
|
// removed in the OP_MSG request first section, and DocumentSequence is not a
|
|
553
599
|
// BSON type and is specific to the MongoDB wire protocol so there's nothing
|
package/src/cmap/connection.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { type DeserializeOptions } from 'bson';
|
|
2
1
|
import { type Readable, Transform, type TransformCallback } from 'stream';
|
|
3
2
|
import { clearTimeout, setTimeout } from 'timers';
|
|
4
3
|
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type BSONSerializeOptions,
|
|
6
|
+
deserialize,
|
|
7
|
+
type DeserializeOptions,
|
|
8
|
+
type Document,
|
|
9
|
+
type ObjectId
|
|
10
|
+
} from '../bson';
|
|
6
11
|
import { type AutoEncrypter } from '../client-side-encryption/auto_encrypter';
|
|
7
12
|
import {
|
|
8
13
|
CLOSE,
|
|
@@ -237,6 +242,8 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
237
242
|
.on('error', this.onError.bind(this));
|
|
238
243
|
this.socket.on('close', this.onClose.bind(this));
|
|
239
244
|
this.socket.on('timeout', this.onTimeout.bind(this));
|
|
245
|
+
|
|
246
|
+
this.messageStream.pause();
|
|
240
247
|
}
|
|
241
248
|
|
|
242
249
|
public get hello() {
|
|
@@ -439,7 +446,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
439
446
|
zlibCompressionLevel: this.description.zlibCompressionLevel
|
|
440
447
|
});
|
|
441
448
|
|
|
442
|
-
if (options.noResponse) {
|
|
449
|
+
if (options.noResponse || message.moreToCome) {
|
|
443
450
|
yield MongoDBResponse.empty;
|
|
444
451
|
return;
|
|
445
452
|
}
|
|
@@ -527,7 +534,11 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
527
534
|
new CommandSucceededEvent(
|
|
528
535
|
this,
|
|
529
536
|
message,
|
|
530
|
-
options.noResponse
|
|
537
|
+
options.noResponse
|
|
538
|
+
? undefined
|
|
539
|
+
: message.moreToCome
|
|
540
|
+
? { ok: 1 }
|
|
541
|
+
: (object ??= document.toObject(bsonOptions)),
|
|
531
542
|
started,
|
|
532
543
|
this.description.serverConnectionId
|
|
533
544
|
)
|
|
@@ -647,6 +658,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
647
658
|
private async *readMany(): AsyncGenerator<OpMsgResponse | OpReply> {
|
|
648
659
|
try {
|
|
649
660
|
this.dataEvents = onData(this.messageStream);
|
|
661
|
+
this.messageStream.resume();
|
|
650
662
|
for await (const message of this.dataEvents) {
|
|
651
663
|
const response = await decompressResponse(message);
|
|
652
664
|
yield response;
|
|
@@ -657,6 +669,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
657
669
|
}
|
|
658
670
|
} finally {
|
|
659
671
|
this.dataEvents = null;
|
|
672
|
+
this.messageStream.pause();
|
|
660
673
|
this.throwIfAborted();
|
|
661
674
|
}
|
|
662
675
|
}
|
|
@@ -11,7 +11,7 @@ const NODE_DRIVER_VERSION = require('../../../package.json').version;
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @public
|
|
14
|
-
* @see https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.
|
|
14
|
+
* @see https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.md#hello-command
|
|
15
15
|
*/
|
|
16
16
|
export interface ClientMetadata {
|
|
17
17
|
driver: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export const MIN_SUPPORTED_SERVER_VERSION = '
|
|
1
|
+
export const MIN_SUPPORTED_SERVER_VERSION = '4.0';
|
|
2
2
|
export const MAX_SUPPORTED_SERVER_VERSION = '8.0';
|
|
3
|
-
export const MIN_SUPPORTED_WIRE_VERSION =
|
|
3
|
+
export const MIN_SUPPORTED_WIRE_VERSION = 7;
|
|
4
4
|
export const MAX_SUPPORTED_WIRE_VERSION = 25;
|
|
5
5
|
export const MIN_SUPPORTED_QE_WIRE_VERSION = 21;
|
|
6
6
|
export const MIN_SUPPORTED_QE_SERVER_VERSION = '7.0';
|