mongodb 6.20.0 → 7.0.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 +17 -18
- package/lib/bulk/common.js +7 -9
- package/lib/bulk/common.js.map +1 -1
- package/lib/change_stream.js +84 -38
- package/lib/change_stream.js.map +1 -1
- package/lib/client-side-encryption/auto_encrypter.js +2 -4
- package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
- package/lib/client-side-encryption/client_encryption.js +2 -3
- package/lib/client-side-encryption/client_encryption.js.map +1 -1
- package/lib/client-side-encryption/errors.js +3 -1
- package/lib/client-side-encryption/errors.js.map +1 -1
- package/lib/client-side-encryption/mongocryptd_manager.js +1 -1
- package/lib/client-side-encryption/mongocryptd_manager.js.map +1 -1
- package/lib/cmap/auth/aws_temporary_credentials.js +10 -58
- package/lib/cmap/auth/aws_temporary_credentials.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +0 -15
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js +2 -7
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/auth/providers.js +0 -1
- package/lib/cmap/auth/providers.js.map +1 -1
- package/lib/cmap/connect.js +1 -1
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +28 -27
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +59 -59
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/errors.js +1 -1
- package/lib/cmap/errors.js.map +1 -1
- package/lib/cmap/handshake/client_metadata.js +7 -5
- package/lib/cmap/handshake/client_metadata.js.map +1 -1
- package/lib/cmap/metrics.js +3 -3
- package/lib/cmap/metrics.js.map +1 -1
- package/lib/cmap/wire_protocol/constants.js +3 -1
- package/lib/cmap/wire_protocol/constants.js.map +1 -1
- package/lib/cmap/wire_protocol/on_data.js +0 -1
- package/lib/cmap/wire_protocol/on_data.js.map +1 -1
- package/lib/cmap/wire_protocol/responses.js +2 -2
- package/lib/cmap/wire_protocol/responses.js.map +1 -1
- package/lib/collection.js +1 -1
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +8 -10
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +17 -34
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/change_stream_cursor.js +2 -2
- package/lib/cursor/change_stream_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +37 -26
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/cursor/run_command_cursor.js +1 -1
- package/lib/cursor/run_command_cursor.js.map +1 -1
- package/lib/db.js +6 -6
- package/lib/db.js.map +1 -1
- package/lib/error.js +2 -2
- package/lib/error.js.map +1 -1
- package/lib/gridfs/download.js +5 -5
- package/lib/gridfs/download.js.map +1 -1
- package/lib/gridfs/index.js +9 -9
- package/lib/gridfs/index.js.map +1 -1
- package/lib/gridfs/upload.js +2 -8
- package/lib/gridfs/upload.js.map +1 -1
- package/lib/index.js +2 -4
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +58 -67
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_client_auth_providers.js +0 -6
- package/lib/mongo_client_auth_providers.js.map +1 -1
- package/lib/mongo_logger.js.map +1 -1
- package/lib/mongo_types.js +1 -2
- package/lib/mongo_types.js.map +1 -1
- package/lib/operations/aggregate.js +0 -3
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/create_collection.js +0 -1
- package/lib/operations/create_collection.js.map +1 -1
- package/lib/operations/drop.js +8 -9
- package/lib/operations/drop.js.map +1 -1
- package/lib/operations/end_sessions.js +34 -0
- package/lib/operations/end_sessions.js.map +1 -0
- package/lib/operations/execute_operation.js +3 -1
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js.map +1 -1
- package/lib/read_preference.js +10 -14
- package/lib/read_preference.js.map +1 -1
- package/lib/sdam/server.js +14 -14
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/srv_polling.js +2 -2
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology.js +24 -68
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sessions.js +5 -4
- package/lib/sessions.js.map +1 -1
- package/lib/transactions.js +2 -13
- package/lib/transactions.js.map +1 -1
- package/lib/utils.js +0 -14
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +72 -239
- package/package.json +16 -19
- package/src/bulk/common.ts +9 -11
- package/src/change_stream.ts +85 -37
- package/src/client-side-encryption/auto_encrypter.ts +6 -12
- package/src/client-side-encryption/client_encryption.ts +5 -6
- package/src/client-side-encryption/errors.ts +3 -0
- package/src/cmap/auth/aws_temporary_credentials.ts +12 -70
- package/src/cmap/auth/mongo_credentials.ts +1 -20
- package/src/cmap/auth/mongodb_aws.ts +8 -17
- package/src/cmap/auth/providers.ts +0 -1
- package/src/cmap/connect.ts +1 -1
- package/src/cmap/connection.ts +14 -16
- package/src/cmap/connection_pool.ts +4 -13
- package/src/cmap/errors.ts +1 -1
- package/src/cmap/handshake/client_metadata.ts +18 -26
- package/src/cmap/wire_protocol/constants.ts +2 -0
- package/src/cmap/wire_protocol/on_data.ts +1 -2
- package/src/collection.ts +1 -1
- package/src/connection_string.ts +13 -20
- package/src/cursor/abstract_cursor.ts +12 -49
- package/src/cursor/change_stream_cursor.ts +2 -2
- package/src/cursor/find_cursor.ts +40 -27
- package/src/cursor/run_command_cursor.ts +1 -1
- package/src/error.ts +2 -2
- package/src/gridfs/download.ts +0 -4
- package/src/gridfs/upload.ts +0 -22
- package/src/index.ts +2 -8
- package/src/mongo_client.ts +68 -100
- package/src/mongo_client_auth_providers.ts +0 -8
- package/src/mongo_logger.ts +1 -1
- package/src/mongo_types.ts +1 -2
- package/src/operations/aggregate.ts +0 -6
- package/src/operations/command.ts +0 -12
- package/src/operations/create_collection.ts +0 -3
- package/src/operations/drop.ts +9 -11
- package/src/operations/end_sessions.ts +44 -0
- package/src/operations/execute_operation.ts +6 -2
- package/src/operations/find.ts +2 -11
- package/src/read_preference.ts +0 -9
- package/src/sdam/topology.ts +2 -60
- package/src/sessions.ts +2 -8
- package/src/transactions.ts +2 -17
- package/src/utils.ts +0 -18
- package/tsconfig.json +5 -7
- package/lib/beta.d.ts +0 -9224
- package/lib/beta.js +0 -21
- package/lib/beta.js.map +0 -1
- package/lib/client-side-encryption/crypto_callbacks.js +0 -81
- package/lib/client-side-encryption/crypto_callbacks.js.map +0 -1
- package/lib/resource_management.js +0 -58
- package/lib/resource_management.js.map +0 -1
- package/src/beta.ts +0 -22
- package/src/client-side-encryption/crypto_callbacks.ts +0 -87
- package/src/resource_management.ts +0 -74
package/src/cmap/connect.ts
CHANGED
|
@@ -222,7 +222,7 @@ export async function prepareHandshakeDocument(
|
|
|
222
222
|
const options = authContext.options;
|
|
223
223
|
const compressors = options.compressors ? options.compressors : [];
|
|
224
224
|
const { serverApi } = authContext.connection;
|
|
225
|
-
const clientMetadata: Document = await options.
|
|
225
|
+
const clientMetadata: Document = await options.metadata;
|
|
226
226
|
|
|
227
227
|
const handshakeDoc: HandshakeDocument = {
|
|
228
228
|
[serverApi?.version || options.loadBalanced === true ? 'hello' : LEGACY_HELLO_COMMAND]: 1,
|
package/src/cmap/connection.ts
CHANGED
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
import {
|
|
23
23
|
MongoCompatibilityError,
|
|
24
24
|
MONGODB_ERROR_CODES,
|
|
25
|
-
MongoMissingDependencyError,
|
|
26
25
|
MongoNetworkError,
|
|
27
26
|
MongoNetworkTimeoutError,
|
|
28
27
|
MongoOperationTimeoutError,
|
|
@@ -91,7 +90,6 @@ export interface CommandOptions extends BSONSerializeOptions {
|
|
|
91
90
|
/** Session to use for the operation */
|
|
92
91
|
session?: ClientSession;
|
|
93
92
|
documentsReturnedIn?: string;
|
|
94
|
-
noResponse?: boolean;
|
|
95
93
|
omitMaxTimeMS?: boolean;
|
|
96
94
|
|
|
97
95
|
// TODO(NODE-2802): Currently the CommandOptions take a property willRetryWrite which is a hint
|
|
@@ -139,10 +137,10 @@ export interface ConnectionOptions
|
|
|
139
137
|
tls: boolean;
|
|
140
138
|
noDelay?: boolean;
|
|
141
139
|
socketTimeoutMS?: number;
|
|
140
|
+
/** @internal */
|
|
142
141
|
cancellationToken?: CancellationToken;
|
|
143
|
-
metadata: ClientMetadata;
|
|
144
142
|
/** @internal */
|
|
145
|
-
|
|
143
|
+
metadata: Promise<ClientMetadata>;
|
|
146
144
|
/** @internal */
|
|
147
145
|
mongoLogger?: MongoLogger | undefined;
|
|
148
146
|
}
|
|
@@ -468,7 +466,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
468
466
|
signal: options.signal
|
|
469
467
|
});
|
|
470
468
|
|
|
471
|
-
if (
|
|
469
|
+
if (message.moreToCome) {
|
|
472
470
|
yield MongoDBResponse.empty;
|
|
473
471
|
return;
|
|
474
472
|
}
|
|
@@ -568,11 +566,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
568
566
|
new CommandSucceededEvent(
|
|
569
567
|
this,
|
|
570
568
|
message,
|
|
571
|
-
|
|
572
|
-
? undefined
|
|
573
|
-
: message.moreToCome
|
|
574
|
-
? { ok: 1 }
|
|
575
|
-
: (object ??= document.toObject(bsonOptions)),
|
|
569
|
+
message.moreToCome ? { ok: 1 } : (object ??= document.toObject(bsonOptions)),
|
|
576
570
|
started,
|
|
577
571
|
this.description.serverConnectionId
|
|
578
572
|
)
|
|
@@ -715,7 +709,15 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
715
709
|
}
|
|
716
710
|
}
|
|
717
711
|
|
|
718
|
-
|
|
712
|
+
try {
|
|
713
|
+
if (this.socket.write(buffer)) return;
|
|
714
|
+
} catch (writeError) {
|
|
715
|
+
const networkError = new MongoNetworkError('unexpected error writing to socket', {
|
|
716
|
+
cause: writeError
|
|
717
|
+
});
|
|
718
|
+
this.onError(networkError);
|
|
719
|
+
throw networkError;
|
|
720
|
+
}
|
|
719
721
|
|
|
720
722
|
const drainEvent = once<void>(this.socket, 'drain', options);
|
|
721
723
|
const timeout = options?.timeoutContext?.timeoutForSocketWrite;
|
|
@@ -868,11 +870,7 @@ export class CryptoConnection extends Connection {
|
|
|
868
870
|
): Promise<Document> {
|
|
869
871
|
const { autoEncrypter } = this;
|
|
870
872
|
if (!autoEncrypter) {
|
|
871
|
-
|
|
872
|
-
// @ts-expect-error No cause provided because there is no underlying error.
|
|
873
|
-
throw new MongoMissingDependencyError('No AutoEncrypter available for encryption', {
|
|
874
|
-
dependencyName: 'n/a'
|
|
875
|
-
});
|
|
873
|
+
throw new MongoRuntimeError('No AutoEncrypter available for encryption');
|
|
876
874
|
}
|
|
877
875
|
|
|
878
876
|
const serverWireVersion = maxWireVersion(this);
|
|
@@ -97,15 +97,6 @@ export const PoolState = Object.freeze({
|
|
|
97
97
|
|
|
98
98
|
type PoolState = (typeof PoolState)[keyof typeof PoolState];
|
|
99
99
|
|
|
100
|
-
/**
|
|
101
|
-
* @public
|
|
102
|
-
* @deprecated This interface is deprecated and will be removed in a future release as it is not used
|
|
103
|
-
* in the driver
|
|
104
|
-
*/
|
|
105
|
-
export interface CloseOptions {
|
|
106
|
-
force?: boolean;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
100
|
/** @public */
|
|
110
101
|
export type ConnectionPoolEvents = {
|
|
111
102
|
connectionPoolCreated(event: ConnectionPoolCreatedEvent): void;
|
|
@@ -610,9 +601,9 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
610
601
|
}
|
|
611
602
|
|
|
612
603
|
private createConnection(callback: Callback<Connection>) {
|
|
613
|
-
// Note that metadata
|
|
614
|
-
// been frozen here, so we pull the
|
|
615
|
-
// no
|
|
604
|
+
// Note that metadata may have changed on the client but have
|
|
605
|
+
// been frozen here, so we pull the metadata promise always from the client
|
|
606
|
+
// no matter what options were set at the construction of the pool.
|
|
616
607
|
const connectOptions: ConnectionOptions = {
|
|
617
608
|
...this.options,
|
|
618
609
|
id: this.connectionCounter.next().value,
|
|
@@ -620,7 +611,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
620
611
|
cancellationToken: this.cancellationToken,
|
|
621
612
|
mongoLogger: this.mongoLogger,
|
|
622
613
|
authProviders: this.server.topology.client.s.authProviders,
|
|
623
|
-
|
|
614
|
+
metadata: this.server.topology.client.options.metadata
|
|
624
615
|
};
|
|
625
616
|
|
|
626
617
|
this.pending++;
|
package/src/cmap/errors.ts
CHANGED
|
@@ -56,7 +56,7 @@ export class PoolClearedError extends MongoNetworkError {
|
|
|
56
56
|
super(errorMessage, pool.serverError ? { cause: pool.serverError } : undefined);
|
|
57
57
|
this.address = pool.address;
|
|
58
58
|
|
|
59
|
-
this.addErrorLabel(MongoErrorLabel.
|
|
59
|
+
this.addErrorLabel(MongoErrorLabel.PoolRequestedRetry);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
override get name(): string {
|
|
@@ -27,8 +27,7 @@ export function isDriverInfoEqual(info1: DriverInfo, info2: DriverInfo): boolean
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* @
|
|
31
|
-
* @deprecated This interface will be made internal in the next major release.
|
|
30
|
+
* @internal
|
|
32
31
|
* @see https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.md#hello-command
|
|
33
32
|
*/
|
|
34
33
|
export interface ClientMetadata {
|
|
@@ -48,27 +47,17 @@ export interface ClientMetadata {
|
|
|
48
47
|
};
|
|
49
48
|
/** FaaS environment information */
|
|
50
49
|
env?: {
|
|
51
|
-
name
|
|
50
|
+
name?: 'aws.lambda' | 'gcp.func' | 'azure.func' | 'vercel';
|
|
52
51
|
timeout_sec?: Int32;
|
|
53
52
|
memory_mb?: Int32;
|
|
54
53
|
region?: string;
|
|
55
|
-
|
|
54
|
+
container?: {
|
|
55
|
+
runtime?: string;
|
|
56
|
+
orchestrator?: string;
|
|
57
|
+
};
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
/**
|
|
60
|
-
* @public
|
|
61
|
-
* @deprecated This interface will be made internal in the next major release.
|
|
62
|
-
*/
|
|
63
|
-
export interface ClientMetadataOptions {
|
|
64
|
-
driverInfo?: {
|
|
65
|
-
name?: string;
|
|
66
|
-
version?: string;
|
|
67
|
-
platform?: string;
|
|
68
|
-
};
|
|
69
|
-
appName?: string;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
61
|
/** @internal */
|
|
73
62
|
export class LimitedSizeDocument {
|
|
74
63
|
private document = new Map();
|
|
@@ -116,10 +105,10 @@ type MakeClientMetadataOptions = Pick<MongoOptions, 'appName'>;
|
|
|
116
105
|
* 3. Omit the `env` document entirely.
|
|
117
106
|
* 4. Truncate `platform`. -- special we do not truncate this field
|
|
118
107
|
*/
|
|
119
|
-
export function makeClientMetadata(
|
|
108
|
+
export async function makeClientMetadata(
|
|
120
109
|
driverInfoList: DriverInfo[],
|
|
121
110
|
{ appName = '' }: MakeClientMetadataOptions
|
|
122
|
-
): ClientMetadata {
|
|
111
|
+
): Promise<ClientMetadata> {
|
|
123
112
|
const metadataDocument = new LimitedSizeDocument(512);
|
|
124
113
|
|
|
125
114
|
// Add app name first, it must be sent
|
|
@@ -191,19 +180,21 @@ export function makeClientMetadata(
|
|
|
191
180
|
}
|
|
192
181
|
}
|
|
193
182
|
}
|
|
194
|
-
return metadataDocument.toObject() as ClientMetadata;
|
|
183
|
+
return await addContainerMetadata(metadataDocument.toObject() as ClientMetadata);
|
|
195
184
|
}
|
|
196
185
|
|
|
197
186
|
let dockerPromise: Promise<boolean>;
|
|
187
|
+
type ContainerMetadata = NonNullable<NonNullable<ClientMetadata['env']>['container']>;
|
|
198
188
|
/** @internal */
|
|
199
|
-
async function getContainerMetadata() {
|
|
200
|
-
const containerMetadata: Record<string, any> = {};
|
|
189
|
+
async function getContainerMetadata(): Promise<ContainerMetadata> {
|
|
201
190
|
dockerPromise ??= fileIsAccessible('/.dockerenv');
|
|
202
191
|
const isDocker = await dockerPromise;
|
|
203
192
|
|
|
204
193
|
const { KUBERNETES_SERVICE_HOST = '' } = process.env;
|
|
205
194
|
const isKubernetes = KUBERNETES_SERVICE_HOST.length > 0 ? true : false;
|
|
206
195
|
|
|
196
|
+
const containerMetadata: ContainerMetadata = {};
|
|
197
|
+
|
|
207
198
|
if (isDocker) containerMetadata.runtime = 'docker';
|
|
208
199
|
if (isKubernetes) containerMetadata.orchestrator = 'kubernetes';
|
|
209
200
|
|
|
@@ -215,15 +206,16 @@ async function getContainerMetadata() {
|
|
|
215
206
|
* Re-add each metadata value.
|
|
216
207
|
* Attempt to add new env container metadata, but keep old data if it does not fit.
|
|
217
208
|
*/
|
|
218
|
-
|
|
219
|
-
originalMetadata: ClientMetadata
|
|
220
|
-
): Promise<ClientMetadata> {
|
|
209
|
+
async function addContainerMetadata(originalMetadata: ClientMetadata): Promise<ClientMetadata> {
|
|
221
210
|
const containerMetadata = await getContainerMetadata();
|
|
222
211
|
if (Object.keys(containerMetadata).length === 0) return originalMetadata;
|
|
223
212
|
|
|
224
213
|
const extendedMetadata = new LimitedSizeDocument(512);
|
|
225
214
|
|
|
226
|
-
const extendedEnvMetadata = {
|
|
215
|
+
const extendedEnvMetadata: NonNullable<ClientMetadata['env']> = {
|
|
216
|
+
...originalMetadata?.env,
|
|
217
|
+
container: containerMetadata
|
|
218
|
+
};
|
|
227
219
|
|
|
228
220
|
for (const [key, val] of Object.entries(originalMetadata)) {
|
|
229
221
|
if (key !== 'env') {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export const MIN_SUPPORTED_SERVER_VERSION = '4.2';
|
|
2
2
|
export const MAX_SUPPORTED_SERVER_VERSION = '8.2';
|
|
3
|
+
export const MIN_SUPPORTED_SNAPSHOT_READS_WIRE_VERSION = 13;
|
|
4
|
+
export const MIN_SUPPORTED_SNAPSHOT_READS_SERVER_VERSION = '5.0';
|
|
3
5
|
export const MIN_SUPPORTED_WIRE_VERSION = 8;
|
|
4
6
|
export const MAX_SUPPORTED_WIRE_VERSION = 27;
|
|
5
7
|
export const MIN_SUPPORTED_QE_WIRE_VERSION = 21;
|
|
@@ -49,7 +49,7 @@ export function onData(
|
|
|
49
49
|
/** Set to true only after event listeners have been removed. */
|
|
50
50
|
let finished = false;
|
|
51
51
|
|
|
52
|
-
const iterator: AsyncGenerator<Buffer> = {
|
|
52
|
+
const iterator: AsyncGenerator<Buffer> & AsyncDisposable = {
|
|
53
53
|
next() {
|
|
54
54
|
// First, we consume all unread events
|
|
55
55
|
const value = unconsumedEvents.shift();
|
|
@@ -89,7 +89,6 @@ export function onData(
|
|
|
89
89
|
return this;
|
|
90
90
|
},
|
|
91
91
|
|
|
92
|
-
// Note this should currently not be used, but is required by the AsyncGenerator interface.
|
|
93
92
|
async [Symbol.asyncDispose]() {
|
|
94
93
|
await closeHandler();
|
|
95
94
|
}
|
package/src/collection.ts
CHANGED
|
@@ -546,7 +546,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
546
546
|
// Explicitly set the limit to 1 and singleBatch to true for all commands, per the spec.
|
|
547
547
|
// noCursorTimeout must be unset as well as batchSize.
|
|
548
548
|
// See: https://github.com/mongodb/specifications/blob/master/source/crud/crud.md#findone-api-details
|
|
549
|
-
const {
|
|
549
|
+
const { ...opts } = options;
|
|
550
550
|
opts.singleBatch = true;
|
|
551
551
|
const cursor = this.find(filter, opts).limit(1);
|
|
552
552
|
const result = await cursor.next();
|
package/src/connection_string.ts
CHANGED
|
@@ -7,12 +7,7 @@ import { MongoCredentials } from './cmap/auth/mongo_credentials';
|
|
|
7
7
|
import { AUTH_MECHS_AUTH_SRC_EXTERNAL, AuthMechanism } from './cmap/auth/providers';
|
|
8
8
|
import { Compressor, type CompressorName } from './cmap/wire_protocol/compression';
|
|
9
9
|
import { Encrypter } from './encrypter';
|
|
10
|
-
import {
|
|
11
|
-
MongoAPIError,
|
|
12
|
-
MongoInvalidArgumentError,
|
|
13
|
-
MongoMissingCredentialsError,
|
|
14
|
-
MongoParseError
|
|
15
|
-
} from './error';
|
|
10
|
+
import { MongoAPIError, MongoInvalidArgumentError, MongoParseError } from './error';
|
|
16
11
|
import {
|
|
17
12
|
MongoClient,
|
|
18
13
|
type MongoClientOptions,
|
|
@@ -417,10 +412,18 @@ export function parseOptions(
|
|
|
417
412
|
});
|
|
418
413
|
}
|
|
419
414
|
|
|
420
|
-
if (isAws
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
415
|
+
if (isAws) {
|
|
416
|
+
const { username, password } = mongoOptions.credentials;
|
|
417
|
+
if (username || password) {
|
|
418
|
+
throw new MongoAPIError(
|
|
419
|
+
'username and password cannot be provided when using MONGODB-AWS. Credentials must be provided in a manner that can be read by the AWS SDK.'
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
if (mongoOptions.credentials.mechanismProperties.AWS_SESSION_TOKEN) {
|
|
423
|
+
throw new MongoAPIError(
|
|
424
|
+
'AWS_SESSION_TOKEN cannot be provided when using MONGODB-AWS. Credentials must be provided in a manner that can be read by the AWS SDK.'
|
|
425
|
+
);
|
|
426
|
+
}
|
|
424
427
|
}
|
|
425
428
|
|
|
426
429
|
mongoOptions.credentials.validate();
|
|
@@ -1283,16 +1286,6 @@ export const OPTIONS = {
|
|
|
1283
1286
|
secureProtocol: { type: 'any' },
|
|
1284
1287
|
index: { type: 'any' },
|
|
1285
1288
|
// Legacy options from v3 era
|
|
1286
|
-
useNewUrlParser: {
|
|
1287
|
-
type: 'boolean',
|
|
1288
|
-
deprecated:
|
|
1289
|
-
'useNewUrlParser has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version'
|
|
1290
|
-
} as OptionDescriptor,
|
|
1291
|
-
useUnifiedTopology: {
|
|
1292
|
-
type: 'boolean',
|
|
1293
|
-
deprecated:
|
|
1294
|
-
'useUnifiedTopology has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version'
|
|
1295
|
-
} as OptionDescriptor,
|
|
1296
1289
|
__skipPingOnConnect: { type: 'boolean' }
|
|
1297
1290
|
} as Record<keyof MongoClientOptions, OptionDescriptor>;
|
|
1298
1291
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Readable
|
|
1
|
+
import { Readable } from 'stream';
|
|
2
2
|
|
|
3
3
|
import { type BSONSerializeOptions, type Document, Long, pluckBSONSerializeOptions } from '../bson';
|
|
4
4
|
import { type OnDemandDocumentDeserializeOptions } from '../cmap/wire_protocol/on_demand/document';
|
|
@@ -18,7 +18,6 @@ import { GetMoreOperation } from '../operations/get_more';
|
|
|
18
18
|
import { KillCursorsOperation } from '../operations/kill_cursors';
|
|
19
19
|
import { ReadConcern, type ReadConcernLike } from '../read_concern';
|
|
20
20
|
import { ReadPreference, type ReadPreferenceLike } from '../read_preference';
|
|
21
|
-
import { type AsyncDisposable, configureResourceManagement } from '../resource_management';
|
|
22
21
|
import type { Server } from '../sdam/server';
|
|
23
22
|
import { type ClientSession, maybeClearPinnedConnection } from '../sessions';
|
|
24
23
|
import { type CSOTTimeoutContext, type Timeout, TimeoutContext } from '../timeout';
|
|
@@ -59,12 +58,6 @@ export const CURSOR_FLAGS = [
|
|
|
59
58
|
'partial'
|
|
60
59
|
] as const;
|
|
61
60
|
|
|
62
|
-
/** @public */
|
|
63
|
-
export interface CursorStreamOptions {
|
|
64
|
-
/** A transformation method applied to each document emitted by the stream */
|
|
65
|
-
transform?(this: void, doc: Document): Document;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
61
|
/** @public */
|
|
69
62
|
export type CursorFlag = (typeof CURSOR_FLAGS)[number];
|
|
70
63
|
|
|
@@ -437,13 +430,10 @@ export abstract class AbstractCursor<
|
|
|
437
430
|
}
|
|
438
431
|
|
|
439
432
|
/**
|
|
440
|
-
* @beta
|
|
441
433
|
* @experimental
|
|
442
434
|
* An alias for {@link AbstractCursor.close|AbstractCursor.close()}.
|
|
443
435
|
*/
|
|
444
|
-
|
|
445
|
-
/** @internal */
|
|
446
|
-
async asyncDispose() {
|
|
436
|
+
async [Symbol.asyncDispose]() {
|
|
447
437
|
await this.close();
|
|
448
438
|
}
|
|
449
439
|
|
|
@@ -523,7 +513,7 @@ export abstract class AbstractCursor<
|
|
|
523
513
|
}
|
|
524
514
|
}
|
|
525
515
|
|
|
526
|
-
stream(
|
|
516
|
+
stream(): Readable & AsyncIterable<TSchema> {
|
|
527
517
|
const readable = new ReadableCursorStream(this);
|
|
528
518
|
const abortListener = addAbortListener(this.signal, function () {
|
|
529
519
|
readable.destroy(this.reason);
|
|
@@ -532,31 +522,6 @@ export abstract class AbstractCursor<
|
|
|
532
522
|
abortListener?.[kDispose]();
|
|
533
523
|
});
|
|
534
524
|
|
|
535
|
-
if (options?.transform) {
|
|
536
|
-
const transform = options.transform;
|
|
537
|
-
|
|
538
|
-
const transformedStream = readable.pipe(
|
|
539
|
-
new Transform({
|
|
540
|
-
objectMode: true,
|
|
541
|
-
highWaterMark: 1,
|
|
542
|
-
transform(chunk, _, callback) {
|
|
543
|
-
try {
|
|
544
|
-
const transformed = transform(chunk);
|
|
545
|
-
callback(undefined, transformed);
|
|
546
|
-
} catch (err) {
|
|
547
|
-
callback(err);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
})
|
|
551
|
-
);
|
|
552
|
-
|
|
553
|
-
// Bubble errors to transformed stream, because otherwise no way
|
|
554
|
-
// to handle this error.
|
|
555
|
-
readable.on('error', err => transformedStream.emit('error', err));
|
|
556
|
-
|
|
557
|
-
return transformedStream;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
525
|
return readable;
|
|
561
526
|
}
|
|
562
527
|
|
|
@@ -701,7 +666,11 @@ export abstract class AbstractCursor<
|
|
|
701
666
|
array.push(await this.transformDocument(doc));
|
|
702
667
|
}
|
|
703
668
|
} else {
|
|
704
|
-
array.push(...
|
|
669
|
+
// Note: previous versions of this logic used `array.push(...)`, which adds each item
|
|
670
|
+
// to the callstack. For large arrays, this can exceed the maximum call size.
|
|
671
|
+
for (const doc of docs) {
|
|
672
|
+
array.push(doc);
|
|
673
|
+
}
|
|
705
674
|
}
|
|
706
675
|
}
|
|
707
676
|
return array;
|
|
@@ -893,7 +862,7 @@ export abstract class AbstractCursor<
|
|
|
893
862
|
): Promise<InitialCursorResponse>;
|
|
894
863
|
|
|
895
864
|
/** @internal */
|
|
896
|
-
async getMore(
|
|
865
|
+
async getMore(): Promise<CursorResponse> {
|
|
897
866
|
if (this.cursorId == null) {
|
|
898
867
|
throw new MongoRuntimeError(
|
|
899
868
|
'Unexpected null cursor id. A cursor creating command should have set this'
|
|
@@ -910,11 +879,10 @@ export abstract class AbstractCursor<
|
|
|
910
879
|
'Unexpected null session. A cursor creating command should have set this'
|
|
911
880
|
);
|
|
912
881
|
}
|
|
913
|
-
|
|
914
882
|
const getMoreOptions = {
|
|
915
883
|
...this.cursorOptions,
|
|
916
884
|
session: this.cursorSession,
|
|
917
|
-
batchSize
|
|
885
|
+
batchSize: this.cursorOptions.batchSize
|
|
918
886
|
};
|
|
919
887
|
|
|
920
888
|
const getMoreOperation = new GetMoreOperation(
|
|
@@ -987,14 +955,11 @@ export abstract class AbstractCursor<
|
|
|
987
955
|
await this.cursorInit();
|
|
988
956
|
// If the cursor died or returned documents, return
|
|
989
957
|
if ((this.documents?.length ?? 0) !== 0 || this.isDead) return;
|
|
990
|
-
// Otherwise, run a getMore
|
|
991
958
|
}
|
|
992
959
|
|
|
993
|
-
//
|
|
994
|
-
const batchSize = this.cursorOptions.batchSize || 1000;
|
|
995
|
-
|
|
960
|
+
// Otherwise, run a getMore
|
|
996
961
|
try {
|
|
997
|
-
const response = await this.getMore(
|
|
962
|
+
const response = await this.getMore();
|
|
998
963
|
this.cursorId = response.id;
|
|
999
964
|
this.documents = response;
|
|
1000
965
|
} catch (error) {
|
|
@@ -1223,8 +1188,6 @@ class ReadableCursorStream extends Readable {
|
|
|
1223
1188
|
}
|
|
1224
1189
|
}
|
|
1225
1190
|
|
|
1226
|
-
configureResourceManagement(AbstractCursor.prototype);
|
|
1227
|
-
|
|
1228
1191
|
/**
|
|
1229
1192
|
* @internal
|
|
1230
1193
|
* The cursor timeout context is a wrapper around a timeout context
|
|
@@ -158,8 +158,8 @@ export class ChangeStreamCursor<
|
|
|
158
158
|
return { server, session, response };
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
override async getMore(
|
|
162
|
-
const response = await super.getMore(
|
|
161
|
+
override async getMore(): Promise<CursorResponse> {
|
|
162
|
+
const response = await super.getMore();
|
|
163
163
|
|
|
164
164
|
this.maxWireVersion = maxWireVersion(this.server);
|
|
165
165
|
this._processBatch(response);
|
|
@@ -16,7 +16,7 @@ import { FindOperation, type FindOptions } from '../operations/find';
|
|
|
16
16
|
import type { Hint } from '../operations/operation';
|
|
17
17
|
import type { ClientSession } from '../sessions';
|
|
18
18
|
import { formatSort, type Sort, type SortDirection } from '../sort';
|
|
19
|
-
import { emitWarningOnce, mergeOptions, type MongoDBNamespace, squashError } from '../utils';
|
|
19
|
+
import { emitWarningOnce, mergeOptions, type MongoDBNamespace, noop, squashError } from '../utils';
|
|
20
20
|
import { type InitialCursorResponse } from './abstract_cursor';
|
|
21
21
|
import { ExplainableCursor } from './explainable_cursor';
|
|
22
22
|
|
|
@@ -98,37 +98,50 @@ export class FindCursor<TSchema = any> extends ExplainableCursor<TSchema> {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/** @internal */
|
|
101
|
-
override async getMore(
|
|
101
|
+
override async getMore(): Promise<CursorResponse> {
|
|
102
102
|
const numReturned = this.numReturned;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// is exhausted and return a cursorId of zero.
|
|
120
|
-
// instead, if we determine there are no more documents to request from the server, we preemptively
|
|
121
|
-
// close the cursor
|
|
122
|
-
}
|
|
123
|
-
return CursorResponse.emptyGetMore;
|
|
103
|
+
const limit = this.findOptions.limit ?? Infinity;
|
|
104
|
+
const remaining = limit - numReturned;
|
|
105
|
+
|
|
106
|
+
if (numReturned === limit && !this.id?.isZero()) {
|
|
107
|
+
// this is an optimization for the special case of a limit for a find command to avoid an
|
|
108
|
+
// extra getMore when the limit has been reached and the limit is a multiple of the batchSize.
|
|
109
|
+
// This is a consequence of the new query engine in 5.0 having no knowledge of the limit as it
|
|
110
|
+
// produces results for the find command. Once a batch is filled up, it is returned and only
|
|
111
|
+
// on the subsequent getMore will the query framework consider the limit, determine the cursor
|
|
112
|
+
// is exhausted and return a cursorId of zero.
|
|
113
|
+
// instead, if we determine there are no more documents to request from the server, we preemptively
|
|
114
|
+
// close the cursor
|
|
115
|
+
try {
|
|
116
|
+
await this.close();
|
|
117
|
+
} catch (error) {
|
|
118
|
+
squashError(error);
|
|
124
119
|
}
|
|
120
|
+
return CursorResponse.emptyGetMore;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// TODO(DRIVERS-1448): Remove logic to enforce `limit` in the driver
|
|
124
|
+
let cleanup: () => void = noop;
|
|
125
|
+
const { batchSize } = this.cursorOptions;
|
|
126
|
+
if (batchSize != null && batchSize > remaining) {
|
|
127
|
+
this.cursorOptions.batchSize = remaining;
|
|
128
|
+
|
|
129
|
+
// After executing the final getMore, re-assign the batchSize back to its original value so that
|
|
130
|
+
// if the cursor is rewound and executed, the batchSize is still correct.
|
|
131
|
+
cleanup = () => {
|
|
132
|
+
this.cursorOptions.batchSize = batchSize;
|
|
133
|
+
};
|
|
125
134
|
}
|
|
126
135
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
this.numReturned = this.numReturned + response.batchSize;
|
|
136
|
+
try {
|
|
137
|
+
const response = await super.getMore();
|
|
130
138
|
|
|
131
|
-
|
|
139
|
+
this.numReturned = this.numReturned + response.batchSize;
|
|
140
|
+
|
|
141
|
+
return response;
|
|
142
|
+
} finally {
|
|
143
|
+
cleanup?.();
|
|
144
|
+
}
|
|
132
145
|
}
|
|
133
146
|
|
|
134
147
|
/**
|
|
@@ -159,7 +159,7 @@ export class RunCommandCursor extends AbstractCursor {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
/** @internal */
|
|
162
|
-
override async getMore(
|
|
162
|
+
override async getMore(): Promise<CursorResponse> {
|
|
163
163
|
if (!this.session) {
|
|
164
164
|
throw new MongoRuntimeError(
|
|
165
165
|
'Unexpected null session. A cursor creating command should have set this'
|
package/src/error.ts
CHANGED
|
@@ -97,7 +97,7 @@ export const MongoErrorLabel = Object.freeze({
|
|
|
97
97
|
ResumableChangeStreamError: 'ResumableChangeStreamError',
|
|
98
98
|
HandshakeError: 'HandshakeError',
|
|
99
99
|
ResetPool: 'ResetPool',
|
|
100
|
-
|
|
100
|
+
PoolRequestedRetry: 'PoolRequestedRetry',
|
|
101
101
|
InterruptInUseConnections: 'InterruptInUseConnections',
|
|
102
102
|
NoWritesPerformed: 'NoWritesPerformed'
|
|
103
103
|
} as const);
|
|
@@ -1444,7 +1444,7 @@ export function needsRetryableWriteLabel(
|
|
|
1444
1444
|
export function isRetryableWriteError(error: MongoError): boolean {
|
|
1445
1445
|
return (
|
|
1446
1446
|
error.hasErrorLabel(MongoErrorLabel.RetryableWriteError) ||
|
|
1447
|
-
error.hasErrorLabel(MongoErrorLabel.
|
|
1447
|
+
error.hasErrorLabel(MongoErrorLabel.PoolRequestedRetry)
|
|
1448
1448
|
);
|
|
1449
1449
|
}
|
|
1450
1450
|
|
package/src/gridfs/download.ts
CHANGED
|
@@ -53,10 +53,6 @@ export interface GridFSFile {
|
|
|
53
53
|
filename: string;
|
|
54
54
|
metadata?: Document;
|
|
55
55
|
uploadDate: Date;
|
|
56
|
-
/** @deprecated Will be removed in the next major version. */
|
|
57
|
-
contentType?: string;
|
|
58
|
-
/** @deprecated Will be removed in the next major version. */
|
|
59
|
-
aliases?: string[];
|
|
60
56
|
}
|
|
61
57
|
|
|
62
58
|
/** @internal */
|
package/src/gridfs/upload.ts
CHANGED
|
@@ -32,16 +32,6 @@ export interface GridFSBucketWriteStreamOptions extends WriteConcernOptions {
|
|
|
32
32
|
id?: ObjectId;
|
|
33
33
|
/** Object to store in the file document's `metadata` field */
|
|
34
34
|
metadata?: Document;
|
|
35
|
-
/**
|
|
36
|
-
* String to store in the file document's `contentType` field.
|
|
37
|
-
* @deprecated Will be removed in the next major version. Add a contentType field to the metadata document instead.
|
|
38
|
-
*/
|
|
39
|
-
contentType?: string;
|
|
40
|
-
/**
|
|
41
|
-
* Array of strings to store in the file document's `aliases` field.
|
|
42
|
-
* @deprecated Will be removed in the next major version. Add an aliases field to the metadata document instead.
|
|
43
|
-
*/
|
|
44
|
-
aliases?: string[];
|
|
45
35
|
/**
|
|
46
36
|
* @experimental
|
|
47
37
|
* Specifies the time an operation will run until it throws a timeout error
|
|
@@ -305,8 +295,6 @@ function checkDone(stream: GridFSBucketWriteStream, callback: Callback): void {
|
|
|
305
295
|
stream.length,
|
|
306
296
|
stream.chunkSizeBytes,
|
|
307
297
|
stream.filename,
|
|
308
|
-
stream.options.contentType,
|
|
309
|
-
stream.options.aliases,
|
|
310
298
|
stream.options.metadata
|
|
311
299
|
);
|
|
312
300
|
|
|
@@ -402,8 +390,6 @@ function createFilesDoc(
|
|
|
402
390
|
length: number,
|
|
403
391
|
chunkSize: number,
|
|
404
392
|
filename: string,
|
|
405
|
-
contentType?: string,
|
|
406
|
-
aliases?: string[],
|
|
407
393
|
metadata?: Document
|
|
408
394
|
): GridFSFile {
|
|
409
395
|
const ret: GridFSFile = {
|
|
@@ -414,14 +400,6 @@ function createFilesDoc(
|
|
|
414
400
|
filename
|
|
415
401
|
};
|
|
416
402
|
|
|
417
|
-
if (contentType) {
|
|
418
|
-
ret.contentType = contentType;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
if (aliases) {
|
|
422
|
-
ret.aliases = aliases;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
403
|
if (metadata) {
|
|
426
404
|
ret.metadata = metadata;
|
|
427
405
|
}
|