@depup/mongodb 7.5.0-depup.7 → 7.6.0-depup.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 (108) hide show
  1. package/README.md +4 -4
  2. package/changes.json +3 -3
  3. package/lib/bulk/common.js +27 -5
  4. package/lib/bulk/common.js.map +1 -1
  5. package/lib/bulk/ordered.js +25 -7
  6. package/lib/bulk/ordered.js.map +1 -1
  7. package/lib/bulk/unordered.js +25 -7
  8. package/lib/bulk/unordered.js.map +1 -1
  9. package/lib/client-side-encryption/auto_encrypter.js +8 -2
  10. package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
  11. package/lib/client-side-encryption/client_encryption.js +12 -4
  12. package/lib/client-side-encryption/client_encryption.js.map +1 -1
  13. package/lib/client-side-encryption/kms_options.js +3 -0
  14. package/lib/client-side-encryption/kms_options.js.map +1 -0
  15. package/lib/client-side-encryption/state_machine.js +54 -7
  16. package/lib/client-side-encryption/state_machine.js.map +1 -1
  17. package/lib/cmap/auth/gssapi.js +2 -1
  18. package/lib/cmap/auth/gssapi.js.map +1 -1
  19. package/lib/cmap/auth/mongo_credentials.js +0 -1
  20. package/lib/cmap/auth/mongo_credentials.js.map +1 -1
  21. package/lib/cmap/auth/mongodb_aws.js +0 -3
  22. package/lib/cmap/auth/mongodb_aws.js.map +1 -1
  23. package/lib/cmap/command_monitoring_events.js +6 -7
  24. package/lib/cmap/command_monitoring_events.js.map +1 -1
  25. package/lib/cmap/commands.js +13 -0
  26. package/lib/cmap/commands.js.map +1 -1
  27. package/lib/cmap/connect.js +2 -2
  28. package/lib/cmap/connect.js.map +1 -1
  29. package/lib/cmap/connection.js +3 -1
  30. package/lib/cmap/connection.js.map +1 -1
  31. package/lib/cmap/handshake/client_metadata.js +2 -1
  32. package/lib/cmap/handshake/client_metadata.js.map +1 -1
  33. package/lib/cmap/wire_protocol/constants.js +2 -2
  34. package/lib/connection_string.js +4 -0
  35. package/lib/connection_string.js.map +1 -1
  36. package/lib/cursor/abstract_cursor.js.map +1 -1
  37. package/lib/error.js +7 -11
  38. package/lib/error.js.map +1 -1
  39. package/lib/gridfs/download.js +1 -1
  40. package/lib/gridfs/download.js.map +1 -1
  41. package/lib/index.js.map +1 -1
  42. package/lib/operations/command.js.map +1 -1
  43. package/lib/operations/delete.js +7 -10
  44. package/lib/operations/delete.js.map +1 -1
  45. package/lib/operations/execute_operation.js +29 -2
  46. package/lib/operations/execute_operation.js.map +1 -1
  47. package/lib/operations/find_and_modify.js +1 -5
  48. package/lib/operations/find_and_modify.js.map +1 -1
  49. package/lib/operations/get_more.js +2 -3
  50. package/lib/operations/get_more.js.map +1 -1
  51. package/lib/operations/indexes.js +3 -9
  52. package/lib/operations/indexes.js.map +1 -1
  53. package/lib/operations/insert.js +6 -2
  54. package/lib/operations/insert.js.map +1 -1
  55. package/lib/operations/list_collections.js +2 -3
  56. package/lib/operations/list_collections.js.map +1 -1
  57. package/lib/operations/list_databases.js +2 -2
  58. package/lib/operations/list_databases.js.map +1 -1
  59. package/lib/operations/update.js +6 -2
  60. package/lib/operations/update.js.map +1 -1
  61. package/lib/runtime_adapters.js +15 -16
  62. package/lib/runtime_adapters.js.map +1 -1
  63. package/lib/sdam/server.js +1 -1
  64. package/lib/sdam/server.js.map +1 -1
  65. package/lib/sessions.js +2 -2
  66. package/lib/sessions.js.map +1 -1
  67. package/lib/utils.js +1 -3
  68. package/lib/utils.js.map +1 -1
  69. package/mongodb.d.ts +77 -20
  70. package/package.json +9 -8
  71. package/src/bulk/common.ts +37 -5
  72. package/src/bulk/ordered.ts +23 -7
  73. package/src/bulk/unordered.ts +23 -8
  74. package/src/client-side-encryption/auto_encrypter.ts +19 -3
  75. package/src/client-side-encryption/client_encryption.ts +29 -9
  76. package/src/client-side-encryption/kms_options.ts +93 -0
  77. package/src/client-side-encryption/state_machine.ts +68 -47
  78. package/src/cmap/auth/gssapi.ts +3 -4
  79. package/src/cmap/auth/mongo_credentials.ts +0 -1
  80. package/src/cmap/auth/mongodb_aws.ts +2 -12
  81. package/src/cmap/command_monitoring_events.ts +9 -10
  82. package/src/cmap/commands.ts +17 -0
  83. package/src/cmap/connect.ts +3 -3
  84. package/src/cmap/connection.ts +4 -2
  85. package/src/cmap/handshake/client_metadata.ts +2 -1
  86. package/src/cmap/wire_protocol/constants.ts +2 -2
  87. package/src/connection_string.ts +4 -0
  88. package/src/cursor/abstract_cursor.ts +0 -5
  89. package/src/error.ts +7 -19
  90. package/src/gridfs/download.ts +1 -1
  91. package/src/index.ts +7 -6
  92. package/src/mongo_client.ts +1 -1
  93. package/src/operations/command.ts +0 -5
  94. package/src/operations/delete.ts +17 -15
  95. package/src/operations/execute_operation.ts +29 -2
  96. package/src/operations/find_and_modify.ts +3 -15
  97. package/src/operations/get_more.ts +3 -5
  98. package/src/operations/indexes.ts +6 -16
  99. package/src/operations/insert.ts +13 -2
  100. package/src/operations/list_collections.ts +5 -6
  101. package/src/operations/list_databases.ts +3 -3
  102. package/src/operations/update.ts +9 -2
  103. package/src/operations/validate_collection.ts +1 -1
  104. package/src/runtime_adapters.ts +19 -18
  105. package/src/sdam/server.ts +1 -1
  106. package/src/sessions.ts +2 -5
  107. package/src/utils.ts +1 -3
  108. package/tsconfig.json +9 -2
package/mongodb.d.ts CHANGED
@@ -25,6 +25,7 @@ import { EventEmitter } from 'events';
25
25
  import type { Socket } from 'net';
26
26
  import type { TcpNetConnectOpts } from 'net';
27
27
  import type * as os from 'os';
28
+ import type { Duplex } from 'stream';
28
29
  import { Readable } from 'stream';
29
30
  import { Writable } from 'stream';
30
31
  import type { ConnectionOptions as ConnectionOptions_2 } from 'tls';
@@ -277,11 +278,6 @@ export declare interface AbstractCursorOptions extends BSONSerializeOptions {
277
278
  maxAwaitTimeMS?: number;
278
279
  /**
279
280
  * Comment to apply to the operation.
280
- *
281
- * In server versions pre-4.4, 'comment' must be string. A server
282
- * error will be thrown if any other type is provided.
283
- *
284
- * In server versions 4.4 and above, 'comment' can be any valid BSON type.
285
281
  */
286
282
  comment?: unknown;
287
283
  /**
@@ -821,6 +817,12 @@ export declare interface AutoEncryptionOptions {
821
817
  proxyOptions?: ProxyOptions;
822
818
  /** The TLS options to use connecting to the KMS provider */
823
819
  tlsOptions?: CSFLEKMSTlsOptions;
820
+ /**
821
+ * A callback that establishes the socket used to connect to a KMS host, e.g. to route KMS
822
+ * requests through an HTTP proxy via the HTTP CONNECT method. Mutually exclusive with `proxyOptions`.
823
+ * See {@link KMSConnectCallback} for a usage example.
824
+ */
825
+ kmsConnectCallback?: KMSConnectCallback;
824
826
  }
825
827
 
826
828
  /** @public **/
@@ -933,6 +935,7 @@ export declare class Batch<T = Document> {
933
935
  originalIndexes: number[];
934
936
  batchType: BatchType;
935
937
  operations: T[];
938
+ serializedOperations: Uint8Array[];
936
939
  size: number;
937
940
  sizeBytes: number;
938
941
  constructor(batchType: BatchType, originalZeroIndex: number);
@@ -1047,7 +1050,7 @@ export declare abstract class BulkOperationBase {
1047
1050
  * // Add a replaceOne
1048
1051
  * bulkOp.find({ i: 9 }).replaceOne({writeConcern: { j: 10 }});
1049
1052
  *
1050
- * // Update using a pipeline (requires Mongodb 4.2 or higher)
1053
+ * // Update using a pipeline
1051
1054
  * bulk.find({ k: 11, y: { $exists: true }, z: { $exists: true } }).updateOne([
1052
1055
  * { $set: { total: { $sum: [ '$y', '$z' ] } } }
1053
1056
  * ]);
@@ -1793,6 +1796,7 @@ export declare class ClientEncryption {
1793
1796
  /* Excluded from this release type: _keyVaultClient */
1794
1797
  /* Excluded from this release type: _proxyOptions */
1795
1798
  /* Excluded from this release type: _tlsOptions */
1799
+ /* Excluded from this release type: _kmsConnectCallback */
1796
1800
  /* Excluded from this release type: _kmsProviders */
1797
1801
  /* Excluded from this release type: _timeoutMS */
1798
1802
  /* Excluded from this release type: _mongoCrypt */
@@ -2186,6 +2190,12 @@ export declare interface ClientEncryptionOptions {
2186
2190
  * TLS options for kms providers to use.
2187
2191
  */
2188
2192
  tlsOptions?: CSFLEKMSTlsOptions;
2193
+ /**
2194
+ * A callback that establishes the socket used to connect to a KMS host, e.g. to route KMS
2195
+ * requests through an HTTP proxy via the HTTP CONNECT method. Mutually exclusive with `proxyOptions`.
2196
+ * See {@link KMSConnectCallback} for a usage example.
2197
+ */
2198
+ kmsConnectCallback?: KMSConnectCallback;
2189
2199
  /**
2190
2200
  * Sets the expiration time for the DEK in the cache in milliseconds. Defaults to 60000. 0 means no timeout.
2191
2201
  */
@@ -3267,7 +3277,7 @@ export declare class CommandFailedEvent {
3267
3277
  connectionId?: string | number;
3268
3278
  /**
3269
3279
  * Server generated connection id
3270
- * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server on 4.2+.
3280
+ * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server.
3271
3281
  */
3272
3282
  serverConnectionId: bigint | null;
3273
3283
  requestId: number;
@@ -3295,11 +3305,6 @@ export declare interface CommandOperationOptions extends OperationOptions, Write
3295
3305
  maxTimeMS?: number;
3296
3306
  /**
3297
3307
  * Comment to apply to the operation.
3298
- *
3299
- * In server versions pre-4.4, 'comment' must be string. A server
3300
- * error will be thrown if any other type is provided.
3301
- *
3302
- * In server versions 4.4 and above, 'comment' can be any valid BSON type.
3303
3308
  */
3304
3309
  comment?: unknown;
3305
3310
  dbName?: string;
@@ -3326,7 +3331,7 @@ export declare class CommandStartedEvent {
3326
3331
  /**
3327
3332
  * Server generated connection id
3328
3333
  * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId"
3329
- * from the server on 4.2+.
3334
+ * from the server.
3330
3335
  */
3331
3336
  serverConnectionId: bigint | null;
3332
3337
  serviceId?: ObjectId;
@@ -3346,7 +3351,7 @@ export declare class CommandSucceededEvent {
3346
3351
  connectionId?: string | number;
3347
3352
  /**
3348
3353
  * Server generated connection id
3349
- * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server on 4.2+.
3354
+ * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server.
3350
3355
  */
3351
3356
  serverConnectionId: bigint | null;
3352
3357
  requestId: number;
@@ -3730,7 +3735,7 @@ export declare interface CreateIndexesOptions extends Omit<CommandOperationOptio
3730
3735
  expireAfterSeconds?: number;
3731
3736
  /** Allows users to configure the storage engine on a per-index basis when creating an index. (MongoDB 3.0 or higher) */
3732
3737
  storageEngine?: Document;
3733
- /** (MongoDB 4.4. or higher) Specifies how many data-bearing members of a replica set, including the primary, must complete the index builds successfully before the primary marks the indexes as ready. This option accepts the same values for the "w" field in a write concern plus "votingMembers", which indicates all voting data-bearing nodes. */
3738
+ /** Specifies how many data-bearing members of a replica set, including the primary, must complete the index builds successfully before the primary marks the indexes as ready. This option accepts the same values for the "w" field in a write concern plus "votingMembers", which indicates all voting data-bearing nodes. */
3734
3739
  commitQuorum?: number | string;
3735
3740
  /** Specifies the index version number, either 0 or 1. */
3736
3741
  version?: number;
@@ -3746,7 +3751,7 @@ export declare interface CreateIndexesOptions extends Omit<CommandOperationOptio
3746
3751
  max?: number;
3747
3752
  bucketSize?: number;
3748
3753
  wildcardProjection?: Document;
3749
- /** Specifies that the index should exist on the target collection but should not be used by the query planner when executing operations. (MongoDB 4.4 or higher) */
3754
+ /** Specifies that the index should exist on the target collection but should not be used by the query planner when executing operations. */
3750
3755
  hidden?: boolean;
3751
3756
  }
3752
3757
 
@@ -5303,6 +5308,58 @@ export declare interface KMIPKMSProviderConfiguration {
5303
5308
  endpoint?: string;
5304
5309
  }
5305
5310
 
5311
+ /**
5312
+ * @public
5313
+ *
5314
+ * A callback that establishes the connection to a KMS host.
5315
+ *
5316
+ * When provided on `AutoEncryptionOptions` or `ClientEncryptionOptions`, the driver invokes this
5317
+ * callback instead of connecting to the KMS host itself, passing the target `host` and `port`. The
5318
+ * callback MUST return a `Duplex` stream connected to the KMS host, either directly or tunneled
5319
+ * through a proxy; a `net.Socket` satisfies this, as does any other `Duplex`. The returned stream is
5320
+ * passed to Node.js' `tls.connect()` as its `socket`, and the driver performs the KMS host's TLS
5321
+ * handshake over it using the KMS provider's configured TLS options. The callback therefore MUST NOT
5322
+ * perform the KMS host's TLS handshake itself, though it MAY use TLS for its own transport, e.g. when
5323
+ * connecting to an HTTPS proxy. This enables routing KMS requests through an HTTP proxy via the HTTP
5324
+ * CONNECT method.
5325
+ *
5326
+ * When the operation has a client-side operation timeout (CSOT) configured, `timeoutMS` is the
5327
+ * remaining time budget in milliseconds; it is `undefined` otherwise. The `signal` aborts when the
5328
+ * connection attempt exceeds that budget; the callback should stop connecting and reject when it fires.
5329
+ *
5330
+ * @example <caption>Route KMS requests through an HTTP proxy using the HTTP CONNECT method</caption>
5331
+ * ```ts
5332
+ * import * as net from 'net';
5333
+ *
5334
+ * const kmsConnectCallback: KMSConnectCallback = ({ host, port, signal }) =>
5335
+ * new Promise((resolve, reject) => {
5336
+ * // Open a plain connection to the proxy, not to the KMS host.
5337
+ * const socket = net.connect({ host: 'proxy.example.com', port: 8080, signal });
5338
+ * socket.once('error', reject);
5339
+ * socket.once('connect', () => {
5340
+ * // Ask the proxy to tunnel to the KMS host, then hand the socket back for the driver's TLS.
5341
+ * socket.write(`CONNECT ${host}:${port} HTTP/1.1\r\nHost: ${host}:${port}\r\n\r\n`);
5342
+ * socket.once('data', chunk => {
5343
+ * if (chunk.toString('utf8').startsWith('HTTP/1.1 200')) resolve(socket);
5344
+ * else reject(new Error('Proxy refused the CONNECT request'));
5345
+ * });
5346
+ * });
5347
+ * });
5348
+ *
5349
+ * const clientEncryption = new ClientEncryption(keyVaultClient, {
5350
+ * keyVaultNamespace,
5351
+ * kmsProviders,
5352
+ * kmsConnectCallback
5353
+ * });
5354
+ * ```
5355
+ */
5356
+ export declare type KMSConnectCallback = (options: {
5357
+ host: string;
5358
+ port: number;
5359
+ timeoutMS?: number;
5360
+ signal: AbortSignal;
5361
+ }) => Promise<Duplex>;
5362
+
5306
5363
  /**
5307
5364
  * @public
5308
5365
  * Configuration options that are used by specific KMS providers during key generation, encryption, and decryption.
@@ -5361,11 +5418,11 @@ export declare class ListCollectionsCursor<T extends Pick<CollectionInfo, 'name'
5361
5418
 
5362
5419
  /** @public */
5363
5420
  export declare interface ListCollectionsOptions extends Omit<CommandOperationOptions, 'writeConcern'>, Abortable {
5364
- /** Since 4.0: If true, will only return the collection name in the response, and will omit additional info */
5421
+ /** If true, will only return the collection name in the response, and will omit additional info */
5365
5422
  nameOnly?: boolean;
5366
- /** Since 4.0: If true and nameOnly is true, allows a user without the required privilege (i.e. listCollections action on the database) to run the command when access control is enforced. */
5423
+ /** If true and nameOnly is true, allows a user without the required privilege (i.e. listCollections action on the database) to run the command when access control is enforced. */
5367
5424
  authorizedCollections?: boolean;
5368
- /** The batchSize for the returned command cursor or if pre 2.8 the systems batch collection */
5425
+ /** The batchSize for the returned command cursor */
5369
5426
  batchSize?: number;
5370
5427
  /* Excluded from this release type: timeoutMode */
5371
5428
  /* Excluded from this release type: timeoutContext */
@@ -8889,7 +8946,7 @@ export { UUID }
8889
8946
 
8890
8947
  /** @public */
8891
8948
  export declare interface ValidateCollectionOptions extends Omit<CommandOperationOptions, 'rawData'> {
8892
- /** Validates a collection in the background, without interrupting read or write traffic (only in MongoDB 4.4+) */
8949
+ /** Validates a collection in the background, without interrupting read or write traffic */
8893
8950
  background?: boolean;
8894
8951
  }
8895
8952
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depup/mongodb",
3
- "version": "7.5.0-depup.7",
3
+ "version": "7.6.0-depup.0",
4
4
  "description": "The official MongoDB driver for Node.js (with updated dependencies)",
5
5
  "main": "lib/index.js",
6
6
  "files": [
@@ -32,8 +32,8 @@
32
32
  "email": "dbx-node@mongodb.com"
33
33
  },
34
34
  "dependencies": {
35
- "@mongodb-js/saslprep": "^1.4.12",
36
- "bson": "^7.3.1",
35
+ "@mongodb-js/saslprep": "^1.5.0",
36
+ "bson": "^7.3.2",
37
37
  "mongodb-connection-string-url": "^7.0.2"
38
38
  },
39
39
  "peerDependencies": {
@@ -109,7 +109,7 @@
109
109
  "semver": "^7.7.2",
110
110
  "sinon": "^18.0.1",
111
111
  "sinon-chai": "^4.0.1",
112
- "snappy": "^7.3.2",
112
+ "snappy": "7.3.3",
113
113
  "socks": "^2.8.7",
114
114
  "source-map-support": "^0.5.21",
115
115
  "ts-node": "^10.9.2",
@@ -164,6 +164,7 @@
164
164
  "check:csfle": "npm run build:bundle && nyc mocha --config test/mocha_mongodb.js test/integration/client-side-encryption",
165
165
  "check:snappy": "npm run build:bundle && nyc mocha test/unit/assorted/snappy.test.js",
166
166
  "check:x509": "npm run build:bundle && nyc mocha test/manual/x509_auth.test.ts",
167
+ "check:sfp": "npm run build:bundle && nyc mocha test/manual/sfp.test.ts",
167
168
  "mocha:debug": "npm run build:bundle && node --inspect --enable-source-maps --no-experimental-strip-types ./node_modules/mocha/bin/mocha.js",
168
169
  "build:bundle": "npm run bundle:driver && npm run bundle:types && npm run build:runtime-barrel",
169
170
  "build:runtime-barrel": "node etc/build-runtime-barrel.mjs",
@@ -190,11 +191,11 @@
190
191
  "changes": {
191
192
  "@mongodb-js/saslprep": {
192
193
  "from": "^1.4.11",
193
- "to": "^1.4.12"
194
+ "to": "^1.5.0"
194
195
  },
195
196
  "bson": {
196
197
  "from": "^7.2.0",
197
- "to": "^7.3.1"
198
+ "to": "^7.3.2"
198
199
  },
199
200
  "mongodb-connection-string-url": {
200
201
  "from": "^7.0.1",
@@ -203,8 +204,8 @@
203
204
  },
204
205
  "depsUpdated": 3,
205
206
  "originalPackage": "mongodb",
206
- "originalVersion": "7.5.0",
207
- "processedAt": "2026-07-21T16:17:48.439Z",
207
+ "originalVersion": "7.6.0",
208
+ "processedAt": "2026-08-25T00:16:52.187Z",
208
209
  "smokeTest": "passed"
209
210
  }
210
211
  }
@@ -157,6 +157,7 @@ export class Batch<T = Document> {
157
157
  originalIndexes: number[];
158
158
  batchType: BatchType;
159
159
  operations: T[];
160
+ serializedOperations: Uint8Array[];
160
161
  size: number;
161
162
  sizeBytes: number;
162
163
 
@@ -166,6 +167,7 @@ export class Batch<T = Document> {
166
167
  this.originalIndexes = [];
167
168
  this.batchType = batchType;
168
169
  this.operations = [];
170
+ this.serializedOperations = [];
169
171
  this.size = 0;
170
172
  this.sizeBytes = 0;
171
173
  }
@@ -538,12 +540,31 @@ async function executeCommands(
538
540
  }
539
541
  }
540
542
 
543
+ // The per-operation buffers were serialized in addToOperationsList using the
544
+ // bulk operation's BSON options. Reuse them only when the serialization
545
+ // options in effect for this execution still match, so that BSON options
546
+ // supplied to execute() (e.g. `ignoreUndefined`) are honored. Also skip reuse
547
+ // under auto-encryption, where libmongocrypt requires the plaintext command
548
+ // (document sequences are not permitted per the bulkWrite spec).
549
+ const createdBsonOptions = bulkOperation.s.bsonOptions;
550
+ const canReuseSerialized =
551
+ !bulkOperation.s.usingAutoEncryption &&
552
+ finalOptions.ignoreUndefined === createdBsonOptions.ignoreUndefined &&
553
+ finalOptions.serializeFunctions === createdBsonOptions.serializeFunctions &&
554
+ (finalOptions.checkKeys ?? false) === bulkOperation.s.checkKeys;
555
+ const serialized = canReuseSerialized ? batch.serializedOperations : undefined;
556
+
541
557
  const operation = isInsertBatch(batch)
542
- ? new InsertOperation(bulkOperation.s.namespace, batch.operations, finalOptions)
558
+ ? new InsertOperation(bulkOperation.s.namespace, batch.operations, finalOptions, serialized)
543
559
  : isUpdateBatch(batch)
544
- ? new UpdateOperation(bulkOperation.s.namespace, batch.operations, finalOptions)
560
+ ? new UpdateOperation(bulkOperation.s.namespace, batch.operations, finalOptions, serialized)
545
561
  : isDeleteBatch(batch)
546
- ? new DeleteOperation(bulkOperation.s.namespace, batch.operations, finalOptions)
562
+ ? new DeleteOperation(
563
+ bulkOperation.s.namespace,
564
+ batch.operations,
565
+ finalOptions,
566
+ serialized
567
+ )
547
568
  : null;
548
569
 
549
570
  if (operation == null) throw new MongoRuntimeError(`Unknown batchType: ${batch.batchType}`);
@@ -560,6 +581,15 @@ async function executeCommands(
560
581
  thrownError = error;
561
582
  }
562
583
 
584
+ // Release this batch's serialized buffers now that it has been sent. The
585
+ // operation keeps its own reference to the array for the duration of its
586
+ // execution and any retries, so reassigning here (rather than mutating the
587
+ // shared array) only drops the bulk operation's copy. All batches are built
588
+ // up front, so this does not lower the peak (reached before the first send);
589
+ // it frees each batch's buffers as that batch completes so they are not kept
590
+ // alive through the remaining batches' round trips.
591
+ batch.serializedOperations = [];
592
+
563
593
  if (thrownError != null) {
564
594
  if (thrownError instanceof MongoWriteConcernError) {
565
595
  mergeBatchResults(batch, bulkOperation.s.bulkResult, thrownError, result);
@@ -824,6 +854,7 @@ export interface BulkOperationPrivate {
824
854
  // check keys
825
855
  checkKeys: boolean;
826
856
  bypassDocumentValidation?: boolean;
857
+ usingAutoEncryption: boolean;
827
858
  }
828
859
 
829
860
  /** @public */
@@ -953,7 +984,8 @@ export abstract class BulkOperationBase {
953
984
  // Fundamental error
954
985
  err: undefined,
955
986
  // check keys
956
- checkKeys: typeof options.checkKeys === 'boolean' ? options.checkKeys : false
987
+ checkKeys: typeof options.checkKeys === 'boolean' ? options.checkKeys : false,
988
+ usingAutoEncryption
957
989
  };
958
990
 
959
991
  // bypass Validation
@@ -1011,7 +1043,7 @@ export abstract class BulkOperationBase {
1011
1043
  * // Add a replaceOne
1012
1044
  * bulkOp.find({ i: 9 }).replaceOne({writeConcern: { j: 10 }});
1013
1045
  *
1014
- * // Update using a pipeline (requires Mongodb 4.2 or higher)
1046
+ * // Update using a pipeline
1015
1047
  * bulk.find({ k: 11, y: { $exists: true }, z: { $exists: true } }).updateOne([
1016
1048
  * { $set: { total: { $sum: [ '$y', '$z' ] } } }
1017
1049
  * ]);
@@ -17,13 +17,28 @@ export class OrderedBulkOperation extends BulkOperationBase {
17
17
  batchType: BatchType,
18
18
  document: Document | UpdateStatement | DeleteStatement
19
19
  ): this {
20
- // Get the bsonSize
21
- const bsonSize = BSON.calculateObjectSize(document, {
22
- checkKeys: false,
23
- // Since we don't know what the user selected for BSON options here,
24
- // err on the safe side, and check the size with ignoreUndefined: false.
25
- ignoreUndefined: false
26
- } as any);
20
+ // Serialize the operation once here and reuse the bytes for both the size
21
+ // check/splitting and the wire message (via a DocumentSequence). Under
22
+ // auto-encryption the command is sent as a BSON array rather than a
23
+ // document sequence, so the buffer would never be reused; there we only
24
+ // measure the size and leave `buffer` undefined so nothing is retained on
25
+ // the batch.
26
+ let buffer: Uint8Array | undefined;
27
+ let bsonSize: number;
28
+ if (this.s.usingAutoEncryption) {
29
+ bsonSize = BSON.calculateObjectSize(document, {
30
+ checkKeys: false,
31
+ ignoreUndefined: false
32
+ } as any);
33
+ } else {
34
+ const bson = this.s.bsonOptions;
35
+ buffer = BSON.serialize(document, {
36
+ checkKeys: this.s.checkKeys,
37
+ ignoreUndefined: bson.ignoreUndefined,
38
+ serializeFunctions: bson.serializeFunctions
39
+ });
40
+ bsonSize = buffer.length;
41
+ }
27
42
 
28
43
  // Throw error if the doc is bigger than the max BSON size
29
44
  if (bsonSize >= this.s.maxBsonObjectSize)
@@ -75,6 +90,7 @@ export class OrderedBulkOperation extends BulkOperationBase {
75
90
 
76
91
  this.s.currentBatch.originalIndexes.push(this.s.currentIndex);
77
92
  this.s.currentBatch.operations.push(document);
93
+ if (buffer != null) this.s.currentBatch.serializedOperations.push(buffer);
78
94
  this.s.currentBatchSize += 1;
79
95
  this.s.currentBatchSizeBytes += maxKeySize + bsonSize;
80
96
  this.s.currentIndex += 1;
@@ -31,14 +31,28 @@ export class UnorderedBulkOperation extends BulkOperationBase {
31
31
  batchType: BatchType,
32
32
  document: Document | UpdateStatement | DeleteStatement
33
33
  ): this {
34
- // Get the bsonSize
35
- const bsonSize = BSON.calculateObjectSize(document, {
36
- checkKeys: false,
37
-
38
- // Since we don't know what the user selected for BSON options here,
39
- // err on the safe side, and check the size with ignoreUndefined: false.
40
- ignoreUndefined: false
41
- } as any);
34
+ // Serialize the operation once here and reuse the bytes for both the size
35
+ // check/splitting and the wire message (via a DocumentSequence). Under
36
+ // auto-encryption the command is sent as a BSON array rather than a
37
+ // document sequence, so the buffer would never be reused; there we only
38
+ // measure the size and leave `buffer` undefined so nothing is retained on
39
+ // the batch.
40
+ let buffer: Uint8Array | undefined;
41
+ let bsonSize: number;
42
+ if (this.s.usingAutoEncryption) {
43
+ bsonSize = BSON.calculateObjectSize(document, {
44
+ checkKeys: false,
45
+ ignoreUndefined: false
46
+ } as any);
47
+ } else {
48
+ const bson = this.s.bsonOptions;
49
+ buffer = BSON.serialize(document, {
50
+ checkKeys: this.s.checkKeys,
51
+ ignoreUndefined: bson.ignoreUndefined,
52
+ serializeFunctions: bson.serializeFunctions
53
+ });
54
+ bsonSize = buffer.length;
55
+ }
42
56
 
43
57
  // Throw error if the doc is bigger than the max BSON size
44
58
  if (bsonSize >= this.s.maxBsonObjectSize) {
@@ -90,6 +104,7 @@ export class UnorderedBulkOperation extends BulkOperationBase {
90
104
  }
91
105
 
92
106
  this.s.currentBatch.operations.push(document);
107
+ if (buffer != null) this.s.currentBatch.serializedOperations.push(buffer);
93
108
  this.s.currentBatch.originalIndexes.push(this.s.currentIndex);
94
109
  this.s.currentIndex = this.s.currentIndex + 1;
95
110
 
@@ -11,6 +11,7 @@ import { type Abortable } from '../mongo_types';
11
11
  import { MongoDBCollectionNamespace } from '../utils';
12
12
  import { autoSelectSocketOptions } from './client_encryption';
13
13
  import { defaultErrorWrapper, MongoCryptInvalidArgumentError } from './errors';
14
+ import { type CSFLEKMSTlsOptions, type KMSConnectCallback } from './kms_options';
14
15
  import { MongocryptdManager } from './mongocryptd_manager';
15
16
  import {
16
17
  type CredentialProviders,
@@ -18,7 +19,7 @@ import {
18
19
  type KMSProviders,
19
20
  refreshKMSCredentials
20
21
  } from './providers';
21
- import { type CSFLEKMSTlsOptions, StateMachine } from './state_machine';
22
+ import { StateMachine } from './state_machine';
22
23
 
23
24
  /** @public */
24
25
  export interface AutoEncryptionOptions {
@@ -110,6 +111,12 @@ export interface AutoEncryptionOptions {
110
111
  proxyOptions?: ProxyOptions;
111
112
  /** The TLS options to use connecting to the KMS provider */
112
113
  tlsOptions?: CSFLEKMSTlsOptions;
114
+ /**
115
+ * A callback that establishes the socket used to connect to a KMS host, e.g. to route KMS
116
+ * requests through an HTTP proxy via the HTTP CONNECT method. Mutually exclusive with `proxyOptions`.
117
+ * See {@link KMSConnectCallback} for a usage example.
118
+ */
119
+ kmsConnectCallback?: KMSConnectCallback;
113
120
  }
114
121
 
115
122
  /**
@@ -156,6 +163,7 @@ export class AutoEncrypter {
156
163
  _metaDataClient: MongoClient;
157
164
  _proxyOptions: ProxyOptions;
158
165
  _tlsOptions: CSFLEKMSTlsOptions;
166
+ _kmsConnectCallback?: KMSConnectCallback;
159
167
  _kmsProviders: KMSProviders;
160
168
  _bypassMongocryptdAndCryptShared: boolean;
161
169
  _contextCounter: number;
@@ -242,7 +250,13 @@ export class AutoEncrypter {
242
250
  this._keyVaultClient = options.keyVaultClient || client;
243
251
  this._metaDataClient = options.metadataClient || client;
244
252
  this._proxyOptions = options.proxyOptions || {};
253
+ if (this._proxyOptions.proxyHost && options.kmsConnectCallback) {
254
+ throw new MongoCryptInvalidArgumentError(
255
+ 'Cannot set both proxyOptions and kmsConnectCallback'
256
+ );
257
+ }
245
258
  this._tlsOptions = options.tlsOptions || {};
259
+ this._kmsConnectCallback = options.kmsConnectCallback;
246
260
  this._kmsProviders = options.kmsProviders || {};
247
261
  this._credentialProviders = options.credentialProviders;
248
262
 
@@ -417,7 +431,8 @@ export class AutoEncrypter {
417
431
  promoteLongs: false,
418
432
  proxyOptions: this._proxyOptions,
419
433
  tlsOptions: this._tlsOptions,
420
- socketOptions: autoSelectSocketOptions(this._client.s.options)
434
+ socketOptions: autoSelectSocketOptions(this._client.s.options),
435
+ kmsConnectCallback: this._kmsConnectCallback
421
436
  });
422
437
 
423
438
  return deserialize(await stateMachine.execute(this, context, options), {
@@ -443,7 +458,8 @@ export class AutoEncrypter {
443
458
  ...options,
444
459
  proxyOptions: this._proxyOptions,
445
460
  tlsOptions: this._tlsOptions,
446
- socketOptions: autoSelectSocketOptions(this._client.s.options)
461
+ socketOptions: autoSelectSocketOptions(this._client.s.options),
462
+ kmsConnectCallback: this._kmsConnectCallback
447
463
  });
448
464
 
449
465
  return await stateMachine.execute(this, context, options);
@@ -31,6 +31,11 @@ import {
31
31
  MongoCryptCreateEncryptedCollectionError,
32
32
  MongoCryptInvalidArgumentError
33
33
  } from './errors';
34
+ import {
35
+ type ClientEncryptionSocketOptions,
36
+ type CSFLEKMSTlsOptions,
37
+ type KMSConnectCallback
38
+ } from './kms_options';
34
39
  import {
35
40
  type ClientEncryptionDataKeyProvider,
36
41
  type CredentialProviders,
@@ -38,11 +43,7 @@ import {
38
43
  type KMSProviders,
39
44
  refreshKMSCredentials
40
45
  } from './providers/index';
41
- import {
42
- type ClientEncryptionSocketOptions,
43
- type CSFLEKMSTlsOptions,
44
- StateMachine
45
- } from './state_machine';
46
+ import { StateMachine } from './state_machine';
46
47
 
47
48
  /**
48
49
  * @public
@@ -75,6 +76,8 @@ export class ClientEncryption {
75
76
  /** @internal */
76
77
  _tlsOptions: CSFLEKMSTlsOptions;
77
78
  /** @internal */
79
+ _kmsConnectCallback?: KMSConnectCallback;
80
+ /** @internal */
78
81
  _kmsProviders: KMSProviders;
79
82
  /** @internal */
80
83
  _timeoutMS?: number;
@@ -125,7 +128,13 @@ export class ClientEncryption {
125
128
  constructor(client: MongoClient, options: ClientEncryptionOptions) {
126
129
  this._client = client;
127
130
  this._proxyOptions = options.proxyOptions ?? {};
131
+ if (this._proxyOptions.proxyHost && options.kmsConnectCallback) {
132
+ throw new MongoCryptInvalidArgumentError(
133
+ 'Cannot set both proxyOptions and kmsConnectCallback'
134
+ );
135
+ }
128
136
  this._tlsOptions = options.tlsOptions ?? {};
137
+ this._kmsConnectCallback = options.kmsConnectCallback;
129
138
  this._kmsProviders = options.kmsProviders || {};
130
139
  const { timeoutMS } = resolveTimeoutOptions(client, options);
131
140
  this._timeoutMS = timeoutMS;
@@ -226,7 +235,8 @@ export class ClientEncryption {
226
235
  const stateMachine = new StateMachine({
227
236
  proxyOptions: this._proxyOptions,
228
237
  tlsOptions: this._tlsOptions,
229
- socketOptions: autoSelectSocketOptions(this._client.s.options)
238
+ socketOptions: autoSelectSocketOptions(this._client.s.options),
239
+ kmsConnectCallback: this._kmsConnectCallback
230
240
  });
231
241
 
232
242
  const timeoutContext =
@@ -295,7 +305,8 @@ export class ClientEncryption {
295
305
  const stateMachine = new StateMachine({
296
306
  proxyOptions: this._proxyOptions,
297
307
  tlsOptions: this._tlsOptions,
298
- socketOptions: autoSelectSocketOptions(this._client.s.options)
308
+ socketOptions: autoSelectSocketOptions(this._client.s.options),
309
+ kmsConnectCallback: this._kmsConnectCallback
299
310
  });
300
311
 
301
312
  const timeoutContext = TimeoutContext.create(
@@ -699,7 +710,8 @@ export class ClientEncryption {
699
710
  const stateMachine = new StateMachine({
700
711
  proxyOptions: this._proxyOptions,
701
712
  tlsOptions: this._tlsOptions,
702
- socketOptions: autoSelectSocketOptions(this._client.s.options)
713
+ socketOptions: autoSelectSocketOptions(this._client.s.options),
714
+ kmsConnectCallback: this._kmsConnectCallback
703
715
  });
704
716
 
705
717
  const timeoutContext =
@@ -797,7 +809,8 @@ export class ClientEncryption {
797
809
  const stateMachine = new StateMachine({
798
810
  proxyOptions: this._proxyOptions,
799
811
  tlsOptions: this._tlsOptions,
800
- socketOptions: autoSelectSocketOptions(this._client.s.options)
812
+ socketOptions: autoSelectSocketOptions(this._client.s.options),
813
+ kmsConnectCallback: this._kmsConnectCallback
801
814
  });
802
815
  const context = this._mongoCrypt.makeExplicitEncryptionContext(valueBuffer, contextOptions);
803
816
 
@@ -961,6 +974,13 @@ export interface ClientEncryptionOptions {
961
974
  */
962
975
  tlsOptions?: CSFLEKMSTlsOptions;
963
976
 
977
+ /**
978
+ * A callback that establishes the socket used to connect to a KMS host, e.g. to route KMS
979
+ * requests through an HTTP proxy via the HTTP CONNECT method. Mutually exclusive with `proxyOptions`.
980
+ * See {@link KMSConnectCallback} for a usage example.
981
+ */
982
+ kmsConnectCallback?: KMSConnectCallback;
983
+
964
984
  /**
965
985
  * Sets the expiration time for the DEK in the cache in milliseconds. Defaults to 60000. 0 means no timeout.
966
986
  */