@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.
- package/README.md +4 -4
- package/changes.json +3 -3
- package/lib/bulk/common.js +27 -5
- package/lib/bulk/common.js.map +1 -1
- package/lib/bulk/ordered.js +25 -7
- package/lib/bulk/ordered.js.map +1 -1
- package/lib/bulk/unordered.js +25 -7
- package/lib/bulk/unordered.js.map +1 -1
- package/lib/client-side-encryption/auto_encrypter.js +8 -2
- package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
- package/lib/client-side-encryption/client_encryption.js +12 -4
- package/lib/client-side-encryption/client_encryption.js.map +1 -1
- package/lib/client-side-encryption/kms_options.js +3 -0
- package/lib/client-side-encryption/kms_options.js.map +1 -0
- package/lib/client-side-encryption/state_machine.js +54 -7
- package/lib/client-side-encryption/state_machine.js.map +1 -1
- package/lib/cmap/auth/gssapi.js +2 -1
- package/lib/cmap/auth/gssapi.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +0 -1
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js +0 -3
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +6 -7
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/commands.js +13 -0
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connect.js +2 -2
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +3 -1
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/handshake/client_metadata.js +2 -1
- package/lib/cmap/handshake/client_metadata.js.map +1 -1
- package/lib/cmap/wire_protocol/constants.js +2 -2
- package/lib/connection_string.js +4 -0
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/error.js +7 -11
- package/lib/error.js.map +1 -1
- package/lib/gridfs/download.js +1 -1
- package/lib/gridfs/download.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/delete.js +7 -10
- package/lib/operations/delete.js.map +1 -1
- package/lib/operations/execute_operation.js +29 -2
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find_and_modify.js +1 -5
- package/lib/operations/find_and_modify.js.map +1 -1
- package/lib/operations/get_more.js +2 -3
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +3 -9
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/insert.js +6 -2
- package/lib/operations/insert.js.map +1 -1
- package/lib/operations/list_collections.js +2 -3
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/list_databases.js +2 -2
- package/lib/operations/list_databases.js.map +1 -1
- package/lib/operations/update.js +6 -2
- package/lib/operations/update.js.map +1 -1
- package/lib/runtime_adapters.js +15 -16
- package/lib/runtime_adapters.js.map +1 -1
- package/lib/sdam/server.js +1 -1
- package/lib/sdam/server.js.map +1 -1
- package/lib/sessions.js +2 -2
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +1 -3
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +77 -20
- package/package.json +9 -8
- package/src/bulk/common.ts +37 -5
- package/src/bulk/ordered.ts +23 -7
- package/src/bulk/unordered.ts +23 -8
- package/src/client-side-encryption/auto_encrypter.ts +19 -3
- package/src/client-side-encryption/client_encryption.ts +29 -9
- package/src/client-side-encryption/kms_options.ts +93 -0
- package/src/client-side-encryption/state_machine.ts +68 -47
- package/src/cmap/auth/gssapi.ts +3 -4
- package/src/cmap/auth/mongo_credentials.ts +0 -1
- package/src/cmap/auth/mongodb_aws.ts +2 -12
- package/src/cmap/command_monitoring_events.ts +9 -10
- package/src/cmap/commands.ts +17 -0
- package/src/cmap/connect.ts +3 -3
- package/src/cmap/connection.ts +4 -2
- package/src/cmap/handshake/client_metadata.ts +2 -1
- package/src/cmap/wire_protocol/constants.ts +2 -2
- package/src/connection_string.ts +4 -0
- package/src/cursor/abstract_cursor.ts +0 -5
- package/src/error.ts +7 -19
- package/src/gridfs/download.ts +1 -1
- package/src/index.ts +7 -6
- package/src/mongo_client.ts +1 -1
- package/src/operations/command.ts +0 -5
- package/src/operations/delete.ts +17 -15
- package/src/operations/execute_operation.ts +29 -2
- package/src/operations/find_and_modify.ts +3 -15
- package/src/operations/get_more.ts +3 -5
- package/src/operations/indexes.ts +6 -16
- package/src/operations/insert.ts +13 -2
- package/src/operations/list_collections.ts +5 -6
- package/src/operations/list_databases.ts +3 -3
- package/src/operations/update.ts +9 -2
- package/src/operations/validate_collection.ts +1 -1
- package/src/runtime_adapters.ts +19 -18
- package/src/sdam/server.ts +1 -1
- package/src/sessions.ts +2 -5
- package/src/utils.ts +1 -3
- package/tsconfig.json +9 -2
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type Duplex } from 'stream';
|
|
2
|
+
|
|
3
|
+
import { type MongoClientOptions } from '../mongo_client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @public
|
|
7
|
+
*
|
|
8
|
+
* TLS options to use when connecting. The spec specifically calls out which insecure
|
|
9
|
+
* tls options are not allowed:
|
|
10
|
+
*
|
|
11
|
+
* - tlsAllowInvalidCertificates
|
|
12
|
+
* - tlsAllowInvalidHostnames
|
|
13
|
+
* - tlsInsecure
|
|
14
|
+
*
|
|
15
|
+
* These options are not included in the type, and are ignored if provided.
|
|
16
|
+
*/
|
|
17
|
+
export type ClientEncryptionTlsOptions = Pick<
|
|
18
|
+
MongoClientOptions,
|
|
19
|
+
'tlsCAFile' | 'tlsCertificateKeyFile' | 'tlsCertificateKeyFilePassword' | 'secureContext'
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
/** @public */
|
|
23
|
+
export type CSFLEKMSTlsOptions = {
|
|
24
|
+
aws?: ClientEncryptionTlsOptions;
|
|
25
|
+
gcp?: ClientEncryptionTlsOptions;
|
|
26
|
+
kmip?: ClientEncryptionTlsOptions;
|
|
27
|
+
local?: ClientEncryptionTlsOptions;
|
|
28
|
+
azure?: ClientEncryptionTlsOptions;
|
|
29
|
+
|
|
30
|
+
[key: string]: ClientEncryptionTlsOptions | undefined;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @public
|
|
35
|
+
*
|
|
36
|
+
* Socket options to use for KMS requests.
|
|
37
|
+
*/
|
|
38
|
+
export type ClientEncryptionSocketOptions = Pick<
|
|
39
|
+
MongoClientOptions,
|
|
40
|
+
'autoSelectFamily' | 'autoSelectFamilyAttemptTimeout'
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @public
|
|
45
|
+
*
|
|
46
|
+
* A callback that establishes the connection to a KMS host.
|
|
47
|
+
*
|
|
48
|
+
* When provided on `AutoEncryptionOptions` or `ClientEncryptionOptions`, the driver invokes this
|
|
49
|
+
* callback instead of connecting to the KMS host itself, passing the target `host` and `port`. The
|
|
50
|
+
* callback MUST return a `Duplex` stream connected to the KMS host, either directly or tunneled
|
|
51
|
+
* through a proxy; a `net.Socket` satisfies this, as does any other `Duplex`. The returned stream is
|
|
52
|
+
* passed to Node.js' `tls.connect()` as its `socket`, and the driver performs the KMS host's TLS
|
|
53
|
+
* handshake over it using the KMS provider's configured TLS options. The callback therefore MUST NOT
|
|
54
|
+
* perform the KMS host's TLS handshake itself, though it MAY use TLS for its own transport, e.g. when
|
|
55
|
+
* connecting to an HTTPS proxy. This enables routing KMS requests through an HTTP proxy via the HTTP
|
|
56
|
+
* CONNECT method.
|
|
57
|
+
*
|
|
58
|
+
* When the operation has a client-side operation timeout (CSOT) configured, `timeoutMS` is the
|
|
59
|
+
* remaining time budget in milliseconds; it is `undefined` otherwise. The `signal` aborts when the
|
|
60
|
+
* connection attempt exceeds that budget; the callback should stop connecting and reject when it fires.
|
|
61
|
+
*
|
|
62
|
+
* @example <caption>Route KMS requests through an HTTP proxy using the HTTP CONNECT method</caption>
|
|
63
|
+
* ```ts
|
|
64
|
+
* import * as net from 'net';
|
|
65
|
+
*
|
|
66
|
+
* const kmsConnectCallback: KMSConnectCallback = ({ host, port, signal }) =>
|
|
67
|
+
* new Promise((resolve, reject) => {
|
|
68
|
+
* // Open a plain connection to the proxy, not to the KMS host.
|
|
69
|
+
* const socket = net.connect({ host: 'proxy.example.com', port: 8080, signal });
|
|
70
|
+
* socket.once('error', reject);
|
|
71
|
+
* socket.once('connect', () => {
|
|
72
|
+
* // Ask the proxy to tunnel to the KMS host, then hand the socket back for the driver's TLS.
|
|
73
|
+
* socket.write(`CONNECT ${host}:${port} HTTP/1.1\r\nHost: ${host}:${port}\r\n\r\n`);
|
|
74
|
+
* socket.once('data', chunk => {
|
|
75
|
+
* if (chunk.toString('utf8').startsWith('HTTP/1.1 200')) resolve(socket);
|
|
76
|
+
* else reject(new Error('Proxy refused the CONNECT request'));
|
|
77
|
+
* });
|
|
78
|
+
* });
|
|
79
|
+
* });
|
|
80
|
+
*
|
|
81
|
+
* const clientEncryption = new ClientEncryption(keyVaultClient, {
|
|
82
|
+
* keyVaultNamespace,
|
|
83
|
+
* kmsProviders,
|
|
84
|
+
* kmsConnectCallback
|
|
85
|
+
* });
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export type KMSConnectCallback = (options: {
|
|
89
|
+
host: string;
|
|
90
|
+
port: number;
|
|
91
|
+
timeoutMS?: number;
|
|
92
|
+
signal: AbortSignal;
|
|
93
|
+
}) => Promise<Duplex>;
|
|
@@ -15,7 +15,7 @@ import { type ProxyOptions } from '../cmap/connection';
|
|
|
15
15
|
import { CursorTimeoutContext } from '../cursor/abstract_cursor';
|
|
16
16
|
import { getSocks, type SocksLib } from '../deps';
|
|
17
17
|
import { MongoOperationTimeoutError } from '../error';
|
|
18
|
-
import { type MongoClient
|
|
18
|
+
import { type MongoClient } from '../mongo_client';
|
|
19
19
|
import { type Abortable } from '../mongo_types';
|
|
20
20
|
import { type CollectionInfo } from '../operations/list_collections';
|
|
21
21
|
import { Timeout, type TimeoutContext, TimeoutError } from '../timeout';
|
|
@@ -28,6 +28,12 @@ import {
|
|
|
28
28
|
} from '../utils';
|
|
29
29
|
import { autoSelectSocketOptions, type DataKey } from './client_encryption';
|
|
30
30
|
import { MongoCryptError } from './errors';
|
|
31
|
+
import {
|
|
32
|
+
type ClientEncryptionSocketOptions,
|
|
33
|
+
type ClientEncryptionTlsOptions,
|
|
34
|
+
type CSFLEKMSTlsOptions,
|
|
35
|
+
type KMSConnectCallback
|
|
36
|
+
} from './kms_options';
|
|
31
37
|
import { type MongocryptdManager } from './mongocryptd_manager';
|
|
32
38
|
import { type KMSProviders } from './providers';
|
|
33
39
|
|
|
@@ -93,44 +99,6 @@ declare module 'mongodb-client-encryption' {
|
|
|
93
99
|
}
|
|
94
100
|
}
|
|
95
101
|
|
|
96
|
-
/**
|
|
97
|
-
* @public
|
|
98
|
-
*
|
|
99
|
-
* TLS options to use when connecting. The spec specifically calls out which insecure
|
|
100
|
-
* tls options are not allowed:
|
|
101
|
-
*
|
|
102
|
-
* - tlsAllowInvalidCertificates
|
|
103
|
-
* - tlsAllowInvalidHostnames
|
|
104
|
-
* - tlsInsecure
|
|
105
|
-
*
|
|
106
|
-
* These options are not included in the type, and are ignored if provided.
|
|
107
|
-
*/
|
|
108
|
-
export type ClientEncryptionTlsOptions = Pick<
|
|
109
|
-
MongoClientOptions,
|
|
110
|
-
'tlsCAFile' | 'tlsCertificateKeyFile' | 'tlsCertificateKeyFilePassword' | 'secureContext'
|
|
111
|
-
>;
|
|
112
|
-
|
|
113
|
-
/** @public */
|
|
114
|
-
export type CSFLEKMSTlsOptions = {
|
|
115
|
-
aws?: ClientEncryptionTlsOptions;
|
|
116
|
-
gcp?: ClientEncryptionTlsOptions;
|
|
117
|
-
kmip?: ClientEncryptionTlsOptions;
|
|
118
|
-
local?: ClientEncryptionTlsOptions;
|
|
119
|
-
azure?: ClientEncryptionTlsOptions;
|
|
120
|
-
|
|
121
|
-
[key: string]: ClientEncryptionTlsOptions | undefined;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* @public
|
|
126
|
-
*
|
|
127
|
-
* Socket options to use for KMS requests.
|
|
128
|
-
*/
|
|
129
|
-
export type ClientEncryptionSocketOptions = Pick<
|
|
130
|
-
MongoClientOptions,
|
|
131
|
-
'autoSelectFamily' | 'autoSelectFamilyAttemptTimeout'
|
|
132
|
-
>;
|
|
133
|
-
|
|
134
102
|
/**
|
|
135
103
|
* This is kind of a hack. For `rewrapManyDataKey`, we have tests that
|
|
136
104
|
* guarantee that when there are no matching keys, `rewrapManyDataKey` returns
|
|
@@ -173,6 +141,9 @@ export type StateMachineOptions = {
|
|
|
173
141
|
|
|
174
142
|
/** Socket specific options we support. */
|
|
175
143
|
socketOptions: ClientEncryptionSocketOptions;
|
|
144
|
+
|
|
145
|
+
/** Optional callback that establishes the KMS socket, if set. */
|
|
146
|
+
kmsConnectCallback?: KMSConnectCallback;
|
|
176
147
|
} & Pick<BSONSerializeOptions, 'promoteLongs' | 'promoteValues'>;
|
|
177
148
|
|
|
178
149
|
/**
|
|
@@ -388,9 +359,55 @@ export class StateMachine {
|
|
|
388
359
|
}
|
|
389
360
|
|
|
390
361
|
let abortListener;
|
|
362
|
+
let kmsRequestTimeout: Timeout | undefined;
|
|
391
363
|
|
|
392
364
|
try {
|
|
393
|
-
|
|
365
|
+
options?.signal?.throwIfAborted();
|
|
366
|
+
|
|
367
|
+
if (this.options.kmsConnectCallback) {
|
|
368
|
+
const remainingTimeMS = options?.timeoutContext?.csotEnabled()
|
|
369
|
+
? options.timeoutContext.getRemainingTimeMSOrThrow(
|
|
370
|
+
`KMS request timed out after ${options.timeoutContext.timeoutMS}ms`
|
|
371
|
+
)
|
|
372
|
+
: undefined;
|
|
373
|
+
// A non-finite budget (timeoutMS: 0) means no timeout; otherwise back the callback with one.
|
|
374
|
+
const timeoutMS = Number.isFinite(remainingTimeMS) ? remainingTimeMS : undefined;
|
|
375
|
+
const controller = new AbortController();
|
|
376
|
+
// Forward the operation's own abort signal so aborting the operation also aborts the callback.
|
|
377
|
+
const forwardAbort = addAbortListener(options?.signal, function () {
|
|
378
|
+
controller.abort(this.reason);
|
|
379
|
+
});
|
|
380
|
+
const connectPromise = this.options.kmsConnectCallback({
|
|
381
|
+
host: socketOptions.host,
|
|
382
|
+
port: socketOptions.port,
|
|
383
|
+
timeoutMS,
|
|
384
|
+
signal: controller.signal
|
|
385
|
+
});
|
|
386
|
+
// If the callback resolves a socket after we already aborted, close it so it does not leak.
|
|
387
|
+
connectPromise.then(
|
|
388
|
+
resolvedSocket => {
|
|
389
|
+
if (controller.signal.aborted) resolvedSocket.destroy();
|
|
390
|
+
},
|
|
391
|
+
() => null
|
|
392
|
+
);
|
|
393
|
+
const timeout = timeoutMS ? Timeout.expires(timeoutMS) : undefined;
|
|
394
|
+
try {
|
|
395
|
+
socketOptions.socket = timeout
|
|
396
|
+
? await Promise.race([connectPromise, timeout])
|
|
397
|
+
: await connectPromise;
|
|
398
|
+
} catch (err) {
|
|
399
|
+
if (TimeoutError.is(err)) {
|
|
400
|
+
const timeoutError = new MongoOperationTimeoutError('KMS request timed out');
|
|
401
|
+
// Abort with the timeout error as the reason so the callback sees it on `signal.reason`.
|
|
402
|
+
controller.abort(timeoutError);
|
|
403
|
+
throw timeoutError;
|
|
404
|
+
}
|
|
405
|
+
throw onerror(err);
|
|
406
|
+
} finally {
|
|
407
|
+
timeout?.clear();
|
|
408
|
+
forwardAbort?.[kDispose]();
|
|
409
|
+
}
|
|
410
|
+
} else if (this.options.proxyOptions && this.options.proxyOptions.proxyHost) {
|
|
394
411
|
netSocket = new net.Socket();
|
|
395
412
|
|
|
396
413
|
const {
|
|
@@ -465,20 +482,24 @@ export class StateMachine {
|
|
|
465
482
|
resolve();
|
|
466
483
|
}
|
|
467
484
|
});
|
|
468
|
-
|
|
469
|
-
?
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
485
|
+
const remainingTimeMS = options?.timeoutContext?.csotEnabled()
|
|
486
|
+
? options.timeoutContext.getRemainingTimeMSOrThrow(
|
|
487
|
+
`KMS request timed out after ${options.timeoutContext.timeoutMS}ms`
|
|
488
|
+
)
|
|
489
|
+
: undefined;
|
|
490
|
+
const timeoutMS = Number.isFinite(remainingTimeMS) ? remainingTimeMS : undefined;
|
|
491
|
+
kmsRequestTimeout = timeoutMS ? Timeout.expires(timeoutMS) : undefined;
|
|
492
|
+
await (kmsRequestTimeout
|
|
493
|
+
? Promise.race([willResolveKmsRequest, kmsRequestTimeout])
|
|
473
494
|
: willResolveKmsRequest);
|
|
474
495
|
} catch (error) {
|
|
475
|
-
if (error
|
|
476
|
-
throw new MongoOperationTimeoutError('KMS request timed out');
|
|
496
|
+
if (TimeoutError.is(error)) throw new MongoOperationTimeoutError('KMS request timed out');
|
|
477
497
|
throw error;
|
|
478
498
|
} finally {
|
|
479
499
|
// There's no need for any more activity on this socket at this point.
|
|
480
500
|
destroySockets();
|
|
481
501
|
abortListener?.[kDispose]();
|
|
502
|
+
kmsRequestTimeout?.clear();
|
|
482
503
|
}
|
|
483
504
|
}
|
|
484
505
|
|
package/src/cmap/auth/gssapi.ts
CHANGED
|
@@ -69,10 +69,7 @@ export class GSSAPI extends AuthProvider {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
async function makeKerberosClient({
|
|
72
|
-
options: {
|
|
73
|
-
hostAddress,
|
|
74
|
-
runtime: { os }
|
|
75
|
-
},
|
|
72
|
+
options: { hostAddress, runtime },
|
|
76
73
|
credentials
|
|
77
74
|
}: AuthContext): Promise<KerberosClient> {
|
|
78
75
|
if (!hostAddress || typeof hostAddress.host !== 'string' || !credentials) {
|
|
@@ -81,6 +78,8 @@ async function makeKerberosClient({
|
|
|
81
78
|
);
|
|
82
79
|
}
|
|
83
80
|
|
|
81
|
+
const { os } = await runtime;
|
|
82
|
+
|
|
84
83
|
loadKrb();
|
|
85
84
|
if ('kModuleError' in krb) {
|
|
86
85
|
throw krb['kModuleError'];
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { type Binary, type BSONSerializeOptions, ByteUtils } from '../../bson';
|
|
2
2
|
import * as BSON from '../../bson';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
MongoMissingCredentialsError,
|
|
6
|
-
MongoRuntimeError
|
|
7
|
-
} from '../../error';
|
|
8
|
-
import { maxWireVersion, ns, randomBytes } from '../../utils';
|
|
3
|
+
import { MongoMissingCredentialsError, MongoRuntimeError } from '../../error';
|
|
4
|
+
import { ns, randomBytes } from '../../utils';
|
|
9
5
|
import { type AuthContext, AuthProvider } from './auth_provider';
|
|
10
6
|
import {
|
|
11
7
|
type AWSCredentialProvider,
|
|
@@ -45,12 +41,6 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
45
41
|
throw new MongoMissingCredentialsError('AuthContext must provide credentials.');
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
if (maxWireVersion(connection) < 9) {
|
|
49
|
-
throw new MongoCompatibilityError(
|
|
50
|
-
'MONGODB-AWS authentication requires MongoDB version 4.4 or later'
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
44
|
authContext.credentials = await makeTempCredentials(
|
|
55
45
|
authContext.credentials,
|
|
56
46
|
this.credentialFetcher
|
|
@@ -32,7 +32,7 @@ export class CommandStartedEvent {
|
|
|
32
32
|
/**
|
|
33
33
|
* Server generated connection id
|
|
34
34
|
* Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId"
|
|
35
|
-
* from the server
|
|
35
|
+
* from the server.
|
|
36
36
|
*/
|
|
37
37
|
serverConnectionId: bigint | null;
|
|
38
38
|
serviceId?: ObjectId;
|
|
@@ -88,7 +88,7 @@ export class CommandSucceededEvent {
|
|
|
88
88
|
connectionId?: string | number;
|
|
89
89
|
/**
|
|
90
90
|
* Server generated connection id
|
|
91
|
-
* Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server
|
|
91
|
+
* Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server.
|
|
92
92
|
*/
|
|
93
93
|
serverConnectionId: bigint | null;
|
|
94
94
|
requestId: number;
|
|
@@ -148,7 +148,7 @@ export class CommandFailedEvent {
|
|
|
148
148
|
connectionId?: string | number;
|
|
149
149
|
/**
|
|
150
150
|
* Server generated connection id
|
|
151
|
-
* Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server
|
|
151
|
+
* Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server.
|
|
152
152
|
*/
|
|
153
153
|
serverConnectionId: bigint | null;
|
|
154
154
|
requestId: number;
|
|
@@ -249,13 +249,12 @@ const LEGACY_FIND_OPTIONS_MAP = {
|
|
|
249
249
|
function extractCommand(command: WriteProtocolMessageType): Document {
|
|
250
250
|
if (command instanceof OpMsgRequest) {
|
|
251
251
|
const cmd = { ...command.command };
|
|
252
|
-
// For OP_MSG
|
|
253
|
-
// array
|
|
254
|
-
|
|
255
|
-
cmd
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
cmd.nsInfo = cmd.nsInfo.documents;
|
|
252
|
+
// For OP_MSG payload type 1, replace any document-sequence field with its
|
|
253
|
+
// documents array for monitoring (ops, nsInfo, documents, updates, deletes).
|
|
254
|
+
for (const key of Object.keys(cmd)) {
|
|
255
|
+
if (cmd[key] instanceof DocumentSequence) {
|
|
256
|
+
cmd[key] = cmd[key].documents;
|
|
257
|
+
}
|
|
259
258
|
}
|
|
260
259
|
return cmd;
|
|
261
260
|
}
|
package/src/cmap/commands.ts
CHANGED
|
@@ -500,6 +500,23 @@ export class DocumentSequence {
|
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
+
/**
|
|
504
|
+
* Build a DocumentSequence from documents that have already been serialized,
|
|
505
|
+
* reusing the provided buffers instead of re-serializing.
|
|
506
|
+
* @internal
|
|
507
|
+
*/
|
|
508
|
+
export function makeDocumentSequence(
|
|
509
|
+
field: string,
|
|
510
|
+
documents: Document[],
|
|
511
|
+
serialized: Uint8Array[]
|
|
512
|
+
): DocumentSequence {
|
|
513
|
+
const sequence = new DocumentSequence(field);
|
|
514
|
+
for (let i = 0; i < documents.length; i++) {
|
|
515
|
+
sequence.push(documents[i], serialized[i]);
|
|
516
|
+
}
|
|
517
|
+
return sequence;
|
|
518
|
+
}
|
|
519
|
+
|
|
503
520
|
/** @internal */
|
|
504
521
|
export class OpMsgRequest {
|
|
505
522
|
requestId: number;
|
package/src/cmap/connect.ts
CHANGED
|
@@ -174,7 +174,7 @@ export async function performInitialHandshake(
|
|
|
174
174
|
|
|
175
175
|
if (error instanceof MongoError) {
|
|
176
176
|
error.addErrorLabel(MongoErrorLabel.HandshakeError);
|
|
177
|
-
if (needsRetryableWriteLabel(error
|
|
177
|
+
if (needsRetryableWriteLabel(error)) {
|
|
178
178
|
error.addErrorLabel(MongoErrorLabel.RetryableWriteError);
|
|
179
179
|
}
|
|
180
180
|
}
|
|
@@ -224,7 +224,7 @@ export interface HandshakeDocument extends Document {
|
|
|
224
224
|
compression: string[];
|
|
225
225
|
saslSupportedMechs?: string;
|
|
226
226
|
loadBalanced?: boolean;
|
|
227
|
-
backpressure:
|
|
227
|
+
backpressure: '2';
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
/**
|
|
@@ -242,7 +242,7 @@ export async function prepareHandshakeDocument(
|
|
|
242
242
|
|
|
243
243
|
const handshakeDoc: HandshakeDocument = {
|
|
244
244
|
[serverApi?.version || options.loadBalanced === true ? 'hello' : LEGACY_HELLO_COMMAND]: 1,
|
|
245
|
-
backpressure:
|
|
245
|
+
backpressure: '2',
|
|
246
246
|
helloOk: true,
|
|
247
247
|
client: clientMetadata,
|
|
248
248
|
compression: compressors
|
package/src/cmap/connection.ts
CHANGED
|
@@ -146,7 +146,7 @@ export interface ConnectionOptions
|
|
|
146
146
|
/** @internal */
|
|
147
147
|
mongoLogger?: MongoLogger | undefined;
|
|
148
148
|
/** @internal */
|
|
149
|
-
runtime: Runtime
|
|
149
|
+
runtime: Promise<Runtime>;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
/** @public */
|
|
@@ -286,7 +286,9 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
286
286
|
private get supportsOpMsg(): boolean {
|
|
287
287
|
return (
|
|
288
288
|
this.description != null &&
|
|
289
|
-
//
|
|
289
|
+
// OP_MSG was introduced in server 3.6 (wire version 6). This also guards
|
|
290
|
+
// against the pre-handshake case where maxWireVersion() returns 0.
|
|
291
|
+
// TODO(NODE-6672,NODE-6287): remove this helper once OP_QUERY support is dropped
|
|
290
292
|
maxWireVersion(this) >= 6 &&
|
|
291
293
|
!this.description.__nodejs_mock_server__
|
|
292
294
|
);
|
|
@@ -107,8 +107,9 @@ type MakeClientMetadataOptions = Pick<MongoOptions, 'appName' | 'runtime'>;
|
|
|
107
107
|
*/
|
|
108
108
|
export async function makeClientMetadata(
|
|
109
109
|
driverInfoList: DriverInfo[],
|
|
110
|
-
{ appName = '', runtime
|
|
110
|
+
{ appName = '', runtime }: MakeClientMetadataOptions
|
|
111
111
|
): Promise<ClientMetadata> {
|
|
112
|
+
const { os } = await runtime;
|
|
112
113
|
const metadataDocument = new LimitedSizeDocument(512);
|
|
113
114
|
|
|
114
115
|
// Add app name first, it must be sent
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export const MIN_SUPPORTED_SERVER_VERSION = '4.
|
|
1
|
+
export const MIN_SUPPORTED_SERVER_VERSION = '4.4';
|
|
2
2
|
export const MAX_SUPPORTED_SERVER_VERSION = '9.0';
|
|
3
3
|
export const MIN_SUPPORTED_SNAPSHOT_READS_WIRE_VERSION = 13;
|
|
4
4
|
export const MIN_SUPPORTED_SNAPSHOT_READS_SERVER_VERSION = '5.0';
|
|
5
|
-
export const MIN_SUPPORTED_WIRE_VERSION =
|
|
5
|
+
export const MIN_SUPPORTED_WIRE_VERSION = 9;
|
|
6
6
|
export const MAX_SUPPORTED_WIRE_VERSION = 29;
|
|
7
7
|
export const MIN_SUPPORTED_QE_WIRE_VERSION = 21;
|
|
8
8
|
export const MIN_SUPPORTED_QE_SERVER_VERSION = '7.0';
|
package/src/connection_string.ts
CHANGED
|
@@ -544,6 +544,10 @@ export function parseOptions(
|
|
|
544
544
|
);
|
|
545
545
|
|
|
546
546
|
mongoOptions.runtime = resolveRuntimeAdapters(options);
|
|
547
|
+
// Mark the promise as handled so a rejection before any consumer awaits it (possible only in
|
|
548
|
+
// runtimes where the dynamic import of the default os adapter fails) cannot crash the process
|
|
549
|
+
// as an unhandled rejection; consumers awaiting `runtime` still observe the rejection.
|
|
550
|
+
mongoOptions.runtime.then(undefined, squashError);
|
|
547
551
|
|
|
548
552
|
return mongoOptions;
|
|
549
553
|
}
|
|
@@ -126,11 +126,6 @@ export interface AbstractCursorOptions extends BSONSerializeOptions {
|
|
|
126
126
|
maxAwaitTimeMS?: number;
|
|
127
127
|
/**
|
|
128
128
|
* Comment to apply to the operation.
|
|
129
|
-
*
|
|
130
|
-
* In server versions pre-4.4, 'comment' must be string. A server
|
|
131
|
-
* error will be thrown if any other type is provided.
|
|
132
|
-
*
|
|
133
|
-
* In server versions 4.4 and above, 'comment' can be any valid BSON type.
|
|
134
129
|
*/
|
|
135
130
|
comment?: unknown;
|
|
136
131
|
/**
|
package/src/error.ts
CHANGED
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
type ClientBulkWriteError,
|
|
4
4
|
type ClientBulkWriteResult
|
|
5
5
|
} from './operations/client_bulk_write/common';
|
|
6
|
-
import type { ServerType } from './sdam/common';
|
|
7
6
|
import type { TopologyVersion } from './sdam/server_description';
|
|
8
7
|
import type { TopologyDescription } from './sdam/topology_description';
|
|
9
8
|
|
|
@@ -1394,23 +1393,13 @@ const RETRYABLE_READ_ERROR_CODES = new Set<number>([
|
|
|
1394
1393
|
// see: https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.md#terms
|
|
1395
1394
|
const RETRYABLE_WRITE_ERROR_CODES = RETRYABLE_READ_ERROR_CODES;
|
|
1396
1395
|
|
|
1397
|
-
export function needsRetryableWriteLabel(
|
|
1398
|
-
error: Error,
|
|
1399
|
-
maxWireVersion: number,
|
|
1400
|
-
serverType: ServerType
|
|
1401
|
-
): boolean {
|
|
1402
|
-
// pre-4.4 server, then the driver adds an error label for every valid case
|
|
1403
|
-
// execute operation will only inspect the label, code/message logic is handled here
|
|
1396
|
+
export function needsRetryableWriteLabel(error: Error): boolean {
|
|
1404
1397
|
if (error instanceof MongoNetworkError) {
|
|
1405
1398
|
return true;
|
|
1406
1399
|
}
|
|
1407
|
-
|
|
1408
1400
|
if (error instanceof MongoError) {
|
|
1409
|
-
if (
|
|
1410
|
-
|
|
1411
|
-
!error.hasErrorLabel(MongoErrorLabel.HandshakeError)
|
|
1412
|
-
) {
|
|
1413
|
-
// If we already have the error label no need to add it again. 4.4+ servers add the label.
|
|
1401
|
+
if (!error.hasErrorLabel(MongoErrorLabel.HandshakeError)) {
|
|
1402
|
+
// If we already have the error label no need to add it again. servers add the label.
|
|
1414
1403
|
// In the case where we have a handshake error, need to fall down to the logic checking
|
|
1415
1404
|
// the codes.
|
|
1416
1405
|
return false;
|
|
@@ -1418,10 +1407,6 @@ export function needsRetryableWriteLabel(
|
|
|
1418
1407
|
}
|
|
1419
1408
|
|
|
1420
1409
|
if (error instanceof MongoWriteConcernError) {
|
|
1421
|
-
if (serverType === 'Mongos' && maxWireVersion < 9) {
|
|
1422
|
-
// use original top-level code from server response
|
|
1423
|
-
return RETRYABLE_WRITE_ERROR_CODES.has(error.result.code ?? 0);
|
|
1424
|
-
}
|
|
1425
1410
|
const code = error.result.writeConcernError.code ?? Number(error.code);
|
|
1426
1411
|
return RETRYABLE_WRITE_ERROR_CODES.has(Number.isNaN(code) ? 0 : code);
|
|
1427
1412
|
}
|
|
@@ -1551,8 +1536,11 @@ export function isResumableError(error?: Error, wireVersion?: number): boolean {
|
|
|
1551
1536
|
return true;
|
|
1552
1537
|
}
|
|
1553
1538
|
|
|
1539
|
+
// wireVersion of 0 is possible when the server version is unknown (e.g heartbeat failure), so despite
|
|
1540
|
+
// all supported servers being wire version 9+, the >= 9 bound must stay to route "unknown" to the
|
|
1541
|
+
// code-list fallback below to maintain parity.
|
|
1554
1542
|
if (wireVersion != null && wireVersion >= 9) {
|
|
1555
|
-
// DRIVERS-1308:
|
|
1543
|
+
// DRIVERS-1308: Drivers will add a special case to treat the CursorNotFound error code as resumable
|
|
1556
1544
|
if (error.code === MONGODB_ERROR_CODES.CursorNotFound) {
|
|
1557
1545
|
return true;
|
|
1558
1546
|
}
|
package/src/gridfs/download.ts
CHANGED
|
@@ -351,7 +351,7 @@ function init(stream: GridFSBucketReadStream): void {
|
|
|
351
351
|
|
|
352
352
|
const filter: Document = { files_id: doc._id };
|
|
353
353
|
|
|
354
|
-
// Currently
|
|
354
|
+
// Currently the skip function does not support the index,
|
|
355
355
|
// it needs to retrieve all the documents first and then skip them. (CS-25811)
|
|
356
356
|
// As work around we use $gte on the "n" field.
|
|
357
357
|
if (stream.s.options && stream.s.options.start != null) {
|
package/src/index.ts
CHANGED
|
@@ -252,6 +252,12 @@ export {
|
|
|
252
252
|
MongoCryptInvalidArgumentError,
|
|
253
253
|
MongoCryptKMSRequestNetworkTimeoutError
|
|
254
254
|
} from './client-side-encryption/errors';
|
|
255
|
+
export type {
|
|
256
|
+
ClientEncryptionSocketOptions,
|
|
257
|
+
ClientEncryptionTlsOptions,
|
|
258
|
+
CSFLEKMSTlsOptions,
|
|
259
|
+
KMSConnectCallback
|
|
260
|
+
} from './client-side-encryption/kms_options';
|
|
255
261
|
export type { MongocryptdManager } from './client-side-encryption/mongocryptd_manager';
|
|
256
262
|
export type {
|
|
257
263
|
AWSKMSProviderConfiguration,
|
|
@@ -263,12 +269,7 @@ export type {
|
|
|
263
269
|
KMSProviders,
|
|
264
270
|
LocalKMSProviderConfiguration
|
|
265
271
|
} from './client-side-encryption/providers/index';
|
|
266
|
-
export type {
|
|
267
|
-
ClientEncryptionSocketOptions,
|
|
268
|
-
ClientEncryptionTlsOptions,
|
|
269
|
-
CSFLEKMSTlsOptions,
|
|
270
|
-
StateMachineExecutable
|
|
271
|
-
} from './client-side-encryption/state_machine';
|
|
272
|
+
export type { StateMachineExecutable } from './client-side-encryption/state_machine';
|
|
272
273
|
export type { AuthContext, AuthProvider } from './cmap/auth/auth_provider';
|
|
273
274
|
export type {
|
|
274
275
|
AuthMechanismProperties,
|
package/src/mongo_client.ts
CHANGED
|
@@ -46,11 +46,6 @@ export interface CommandOperationOptions
|
|
|
46
46
|
maxTimeMS?: number;
|
|
47
47
|
/**
|
|
48
48
|
* Comment to apply to the operation.
|
|
49
|
-
*
|
|
50
|
-
* In server versions pre-4.4, 'comment' must be string. A server
|
|
51
|
-
* error will be thrown if any other type is provided.
|
|
52
|
-
*
|
|
53
|
-
* In server versions 4.4 and above, 'comment' can be any valid BSON type.
|
|
54
49
|
*/
|
|
55
50
|
comment?: unknown;
|
|
56
51
|
// Admin command overrides.
|
package/src/operations/delete.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Document } from '../bson';
|
|
2
|
+
import { makeDocumentSequence } from '../cmap/commands';
|
|
2
3
|
import { type Connection } from '../cmap/connection';
|
|
3
4
|
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
|
|
4
|
-
import {
|
|
5
|
+
import { MongoServerError } from '../error';
|
|
5
6
|
import type { ClientSession } from '../sessions';
|
|
6
|
-
import {
|
|
7
|
+
import { type MongoDBCollectionNamespace, type MongoDBNamespace } from '../utils';
|
|
7
8
|
import { type WriteConcernOptions } from '../write_concern';
|
|
8
9
|
import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command';
|
|
9
10
|
import { Aspect, defineAspects, type Hint } from './operation';
|
|
@@ -45,12 +46,20 @@ export class DeleteOperation extends CommandOperation<Document> {
|
|
|
45
46
|
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
|
|
46
47
|
override options: DeleteOptions;
|
|
47
48
|
statements: DeleteStatement[];
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
/** @internal */
|
|
50
|
+
serializedOperations?: Uint8Array[];
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
ns: MongoDBNamespace,
|
|
54
|
+
statements: DeleteStatement[],
|
|
55
|
+
options: DeleteOptions,
|
|
56
|
+
serializedOperations?: Uint8Array[]
|
|
57
|
+
) {
|
|
50
58
|
super(undefined, options);
|
|
51
59
|
this.options = options;
|
|
52
60
|
this.ns = ns;
|
|
53
61
|
this.statements = statements;
|
|
62
|
+
this.serializedOperations = serializedOperations;
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
override get commandName() {
|
|
@@ -65,13 +74,15 @@ export class DeleteOperation extends CommandOperation<Document> {
|
|
|
65
74
|
return this.statements.every(op => (op.limit != null ? op.limit > 0 : true));
|
|
66
75
|
}
|
|
67
76
|
|
|
68
|
-
override buildCommandDocument(
|
|
77
|
+
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
|
|
69
78
|
const options = this.options;
|
|
70
79
|
|
|
71
80
|
const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
|
|
72
81
|
const command: Document = {
|
|
73
82
|
delete: this.ns.collection,
|
|
74
|
-
deletes: this.
|
|
83
|
+
deletes: this.serializedOperations
|
|
84
|
+
? makeDocumentSequence('deletes', this.statements, this.serializedOperations)
|
|
85
|
+
: this.statements,
|
|
75
86
|
ordered
|
|
76
87
|
};
|
|
77
88
|
|
|
@@ -85,15 +96,6 @@ export class DeleteOperation extends CommandOperation<Document> {
|
|
|
85
96
|
command.comment = options.comment;
|
|
86
97
|
}
|
|
87
98
|
|
|
88
|
-
const unacknowledgedWrite = this.writeConcern && this.writeConcern.w === 0;
|
|
89
|
-
if (unacknowledgedWrite && maxWireVersion(connection) < 9) {
|
|
90
|
-
if (this.statements.find((o: Document) => o.hint)) {
|
|
91
|
-
throw new MongoCompatibilityError(
|
|
92
|
-
`hint for the delete command is only supported on MongoDB 4.4+`
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
99
|
return command;
|
|
98
100
|
}
|
|
99
101
|
}
|