mongodb 5.2.0 → 5.4.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/lib/admin.js +18 -0
- package/lib/admin.js.map +1 -1
- package/lib/bulk/common.js +28 -7
- package/lib/bulk/common.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +29 -2
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js +5 -3
- package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/cache.js +28 -0
- package/lib/cmap/auth/mongodb_oidc/cache.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js +83 -0
- package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc/callback_workflow.js +138 -112
- package/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/service_workflow.js +4 -2
- package/lib/cmap/auth/mongodb_oidc/service_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js +12 -56
- package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc.js +17 -13
- package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +6 -0
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/connect.js +1 -0
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +12 -12
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +7 -3
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/connection_pool_events.js +28 -3
- package/lib/cmap/connection_pool_events.js.map +1 -1
- package/lib/cmap/handshake/client_metadata.js +173 -0
- package/lib/cmap/handshake/client_metadata.js.map +1 -0
- package/lib/cmap/wire_protocol/constants.js +2 -2
- package/lib/cmap/wire_protocol/shared.js +2 -2
- package/lib/cmap/wire_protocol/shared.js.map +1 -1
- package/lib/collection.js +3 -0
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +48 -53
- package/lib/connection_string.js.map +1 -1
- package/lib/constants.js +11 -0
- package/lib/constants.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +1 -0
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/db.js +18 -0
- package/lib/db.js.map +1 -1
- package/lib/mongo_client.js +16 -0
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_logger.js +258 -27
- package/lib/mongo_logger.js.map +1 -1
- package/lib/operations/add_user.js.map +1 -1
- package/lib/operations/find.js +0 -7
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/run_command.js.map +1 -1
- package/lib/operations/stats.js.map +1 -1
- package/lib/operations/update.js.map +1 -1
- package/lib/sdam/srv_polling.js +1 -15
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology.js.map +1 -1
- package/lib/utils.js +48 -35
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +247 -47
- package/package.json +3 -3
- package/src/admin.ts +18 -0
- package/src/bulk/common.ts +28 -7
- package/src/change_stream.ts +1 -1
- package/src/cmap/auth/mongo_credentials.ts +35 -2
- package/src/cmap/auth/mongodb_oidc/aws_service_workflow.ts +6 -3
- package/src/cmap/auth/mongodb_oidc/cache.ts +27 -0
- package/src/cmap/auth/mongodb_oidc/callback_lock_cache.ts +107 -0
- package/src/cmap/auth/mongodb_oidc/callback_workflow.ts +208 -171
- package/src/cmap/auth/mongodb_oidc/service_workflow.ts +5 -3
- package/src/cmap/auth/mongodb_oidc/token_entry_cache.ts +17 -96
- package/src/cmap/auth/mongodb_oidc.ts +61 -37
- package/src/cmap/command_monitoring_events.ts +13 -1
- package/src/cmap/connect.ts +3 -1
- package/src/cmap/connection.ts +16 -13
- package/src/cmap/connection_pool.ts +14 -4
- package/src/cmap/connection_pool_events.ts +68 -6
- package/src/cmap/handshake/client_metadata.ts +272 -0
- package/src/cmap/wire_protocol/constants.ts +2 -2
- package/src/cmap/wire_protocol/shared.ts +2 -3
- package/src/collection.ts +6 -3
- package/src/connection_string.ts +55 -55
- package/src/constants.ts +11 -0
- package/src/cursor/abstract_cursor.ts +1 -0
- package/src/db.ts +18 -0
- package/src/index.ts +24 -6
- package/src/mongo_client.ts +50 -6
- package/src/mongo_logger.ts +363 -44
- package/src/operations/add_user.ts +8 -2
- package/src/operations/find.ts +0 -10
- package/src/operations/run_command.ts +40 -3
- package/src/operations/stats.ts +11 -2
- package/src/operations/update.ts +8 -4
- package/src/sdam/srv_polling.ts +1 -16
- package/src/sdam/topology.ts +1 -3
- package/src/utils.ts +54 -73
- package/lib/cmap/auth/mongodb_oidc/workflow.js +0 -3
- package/lib/cmap/auth/mongodb_oidc/workflow.js.map +0 -1
- package/src/cmap/auth/mongodb_oidc/workflow.ts +0 -21
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import * as os from 'os';
|
|
2
|
+
import * as process from 'process';
|
|
3
|
+
|
|
4
|
+
import { BSON, Int32 } from '../../bson';
|
|
5
|
+
import { MongoInvalidArgumentError } from '../../error';
|
|
6
|
+
import type { MongoOptions } from '../../mongo_client';
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
9
|
+
const NODE_DRIVER_VERSION = require('../../../package.json').version;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @public
|
|
13
|
+
* @see https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.rst#hello-command
|
|
14
|
+
*/
|
|
15
|
+
export interface ClientMetadata {
|
|
16
|
+
driver: {
|
|
17
|
+
name: string;
|
|
18
|
+
version: string;
|
|
19
|
+
};
|
|
20
|
+
os: {
|
|
21
|
+
type: string;
|
|
22
|
+
name?: NodeJS.Platform;
|
|
23
|
+
architecture?: string;
|
|
24
|
+
version?: string;
|
|
25
|
+
};
|
|
26
|
+
platform: string;
|
|
27
|
+
application?: {
|
|
28
|
+
name: string;
|
|
29
|
+
};
|
|
30
|
+
/** FaaS environment information */
|
|
31
|
+
env?: {
|
|
32
|
+
name: 'aws.lambda' | 'gcp.func' | 'azure.func' | 'vercel';
|
|
33
|
+
timeout_sec?: Int32;
|
|
34
|
+
memory_mb?: Int32;
|
|
35
|
+
region?: string;
|
|
36
|
+
url?: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** @public */
|
|
41
|
+
export interface ClientMetadataOptions {
|
|
42
|
+
driverInfo?: {
|
|
43
|
+
name?: string;
|
|
44
|
+
version?: string;
|
|
45
|
+
platform?: string;
|
|
46
|
+
};
|
|
47
|
+
appName?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** @internal */
|
|
51
|
+
export class LimitedSizeDocument {
|
|
52
|
+
private document = new Map();
|
|
53
|
+
/** BSON overhead: Int32 + Null byte */
|
|
54
|
+
private documentSize = 5;
|
|
55
|
+
constructor(private maxSize: number) {}
|
|
56
|
+
|
|
57
|
+
/** Only adds key/value if the bsonByteLength is less than MAX_SIZE */
|
|
58
|
+
public ifItFitsItSits(key: string, value: Record<string, any> | string): boolean {
|
|
59
|
+
// The BSON byteLength of the new element is the same as serializing it to its own document
|
|
60
|
+
// subtracting the document size int32 and the null terminator.
|
|
61
|
+
const newElementSize = BSON.serialize(new Map().set(key, value)).byteLength - 5;
|
|
62
|
+
|
|
63
|
+
if (newElementSize + this.documentSize > this.maxSize) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.documentSize += newElementSize;
|
|
68
|
+
|
|
69
|
+
this.document.set(key, value);
|
|
70
|
+
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
toObject(): ClientMetadata {
|
|
75
|
+
return BSON.deserialize(BSON.serialize(this.document), {
|
|
76
|
+
promoteLongs: false,
|
|
77
|
+
promoteBuffers: false,
|
|
78
|
+
promoteValues: false,
|
|
79
|
+
useBigInt64: false
|
|
80
|
+
}) as ClientMetadata;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type MakeClientMetadataOptions = Pick<MongoOptions, 'appName' | 'driverInfo'>;
|
|
85
|
+
/**
|
|
86
|
+
* From the specs:
|
|
87
|
+
* Implementors SHOULD cumulatively update fields in the following order until the document is under the size limit:
|
|
88
|
+
* 1. Omit fields from `env` except `env.name`.
|
|
89
|
+
* 2. Omit fields from `os` except `os.type`.
|
|
90
|
+
* 3. Omit the `env` document entirely.
|
|
91
|
+
* 4. Truncate `platform`. -- special we do not truncate this field
|
|
92
|
+
*/
|
|
93
|
+
export function makeClientMetadata(options: MakeClientMetadataOptions): ClientMetadata {
|
|
94
|
+
const metadataDocument = new LimitedSizeDocument(512);
|
|
95
|
+
|
|
96
|
+
const { appName = '' } = options;
|
|
97
|
+
// Add app name first, it must be sent
|
|
98
|
+
if (appName.length > 0) {
|
|
99
|
+
const name =
|
|
100
|
+
Buffer.byteLength(appName, 'utf8') <= 128
|
|
101
|
+
? options.appName
|
|
102
|
+
: Buffer.from(appName, 'utf8').subarray(0, 128).toString('utf8');
|
|
103
|
+
metadataDocument.ifItFitsItSits('application', { name });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const { name = '', version = '', platform = '' } = options.driverInfo;
|
|
107
|
+
|
|
108
|
+
const driverInfo = {
|
|
109
|
+
name: name.length > 0 ? `nodejs|${name}` : 'nodejs',
|
|
110
|
+
version: version.length > 0 ? `${NODE_DRIVER_VERSION}|${version}` : NODE_DRIVER_VERSION
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
if (!metadataDocument.ifItFitsItSits('driver', driverInfo)) {
|
|
114
|
+
throw new MongoInvalidArgumentError(
|
|
115
|
+
'Unable to include driverInfo name and version, metadata cannot exceed 512 bytes'
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let runtimeInfo = getRuntimeInfo();
|
|
120
|
+
if (platform.length > 0) {
|
|
121
|
+
runtimeInfo = `${runtimeInfo}|${platform}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!metadataDocument.ifItFitsItSits('platform', runtimeInfo)) {
|
|
125
|
+
throw new MongoInvalidArgumentError(
|
|
126
|
+
'Unable to include driverInfo platform, metadata cannot exceed 512 bytes'
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Note: order matters, os.type is last so it will be removed last if we're at maxSize
|
|
131
|
+
const osInfo = new Map()
|
|
132
|
+
.set('name', process.platform)
|
|
133
|
+
.set('architecture', process.arch)
|
|
134
|
+
.set('version', os.release())
|
|
135
|
+
.set('type', os.type());
|
|
136
|
+
|
|
137
|
+
if (!metadataDocument.ifItFitsItSits('os', osInfo)) {
|
|
138
|
+
for (const key of osInfo.keys()) {
|
|
139
|
+
osInfo.delete(key);
|
|
140
|
+
if (osInfo.size === 0) break;
|
|
141
|
+
if (metadataDocument.ifItFitsItSits('os', osInfo)) break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const faasEnv = getFAASEnv();
|
|
146
|
+
if (faasEnv != null) {
|
|
147
|
+
if (!metadataDocument.ifItFitsItSits('env', faasEnv)) {
|
|
148
|
+
for (const key of faasEnv.keys()) {
|
|
149
|
+
faasEnv.delete(key);
|
|
150
|
+
if (faasEnv.size === 0) break;
|
|
151
|
+
if (metadataDocument.ifItFitsItSits('env', faasEnv)) break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return metadataDocument.toObject();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Collects FaaS metadata.
|
|
161
|
+
* - `name` MUST be the last key in the Map returned.
|
|
162
|
+
*/
|
|
163
|
+
export function getFAASEnv(): Map<string, string | Int32> | null {
|
|
164
|
+
const {
|
|
165
|
+
AWS_EXECUTION_ENV = '',
|
|
166
|
+
AWS_LAMBDA_RUNTIME_API = '',
|
|
167
|
+
FUNCTIONS_WORKER_RUNTIME = '',
|
|
168
|
+
K_SERVICE = '',
|
|
169
|
+
FUNCTION_NAME = '',
|
|
170
|
+
VERCEL = '',
|
|
171
|
+
AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '',
|
|
172
|
+
AWS_REGION = '',
|
|
173
|
+
FUNCTION_MEMORY_MB = '',
|
|
174
|
+
FUNCTION_REGION = '',
|
|
175
|
+
FUNCTION_TIMEOUT_SEC = '',
|
|
176
|
+
VERCEL_REGION = ''
|
|
177
|
+
} = process.env;
|
|
178
|
+
|
|
179
|
+
const isAWSFaaS = AWS_EXECUTION_ENV.length > 0 || AWS_LAMBDA_RUNTIME_API.length > 0;
|
|
180
|
+
const isAzureFaaS = FUNCTIONS_WORKER_RUNTIME.length > 0;
|
|
181
|
+
const isGCPFaaS = K_SERVICE.length > 0 || FUNCTION_NAME.length > 0;
|
|
182
|
+
const isVercelFaaS = VERCEL.length > 0;
|
|
183
|
+
|
|
184
|
+
// Note: order matters, name must always be the last key
|
|
185
|
+
const faasEnv = new Map();
|
|
186
|
+
|
|
187
|
+
// When isVercelFaaS is true so is isAWSFaaS; Vercel inherits the AWS env
|
|
188
|
+
if (isVercelFaaS && !(isAzureFaaS || isGCPFaaS)) {
|
|
189
|
+
if (VERCEL_REGION.length > 0) {
|
|
190
|
+
faasEnv.set('region', VERCEL_REGION);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
faasEnv.set('name', 'vercel');
|
|
194
|
+
return faasEnv;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (isAWSFaaS && !(isAzureFaaS || isGCPFaaS || isVercelFaaS)) {
|
|
198
|
+
if (AWS_REGION.length > 0) {
|
|
199
|
+
faasEnv.set('region', AWS_REGION);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (
|
|
203
|
+
AWS_LAMBDA_FUNCTION_MEMORY_SIZE.length > 0 &&
|
|
204
|
+
Number.isInteger(+AWS_LAMBDA_FUNCTION_MEMORY_SIZE)
|
|
205
|
+
) {
|
|
206
|
+
faasEnv.set('memory_mb', new Int32(AWS_LAMBDA_FUNCTION_MEMORY_SIZE));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
faasEnv.set('name', 'aws.lambda');
|
|
210
|
+
return faasEnv;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (isAzureFaaS && !(isGCPFaaS || isAWSFaaS || isVercelFaaS)) {
|
|
214
|
+
faasEnv.set('name', 'azure.func');
|
|
215
|
+
return faasEnv;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (isGCPFaaS && !(isAzureFaaS || isAWSFaaS || isVercelFaaS)) {
|
|
219
|
+
if (FUNCTION_REGION.length > 0) {
|
|
220
|
+
faasEnv.set('region', FUNCTION_REGION);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (FUNCTION_MEMORY_MB.length > 0 && Number.isInteger(+FUNCTION_MEMORY_MB)) {
|
|
224
|
+
faasEnv.set('memory_mb', new Int32(FUNCTION_MEMORY_MB));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (FUNCTION_TIMEOUT_SEC.length > 0 && Number.isInteger(+FUNCTION_TIMEOUT_SEC)) {
|
|
228
|
+
faasEnv.set('timeout_sec', new Int32(FUNCTION_TIMEOUT_SEC));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
faasEnv.set('name', 'gcp.func');
|
|
232
|
+
return faasEnv;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @internal
|
|
240
|
+
* This type represents the global Deno object and the minimal type contract we expect it to satisfy.
|
|
241
|
+
*/
|
|
242
|
+
declare const Deno: { version?: { deno?: string } } | undefined;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @internal
|
|
246
|
+
* This type represents the global Bun object and the minimal type contract we expect it to satisfy.
|
|
247
|
+
*/
|
|
248
|
+
declare const Bun: { (): void; version?: string } | undefined;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @internal
|
|
252
|
+
* Get current JavaScript runtime platform
|
|
253
|
+
*
|
|
254
|
+
* NOTE: The version information fetching is intentionally written defensively
|
|
255
|
+
* to avoid having a released driver version that becomes incompatible
|
|
256
|
+
* with a future change to these global objects.
|
|
257
|
+
*/
|
|
258
|
+
function getRuntimeInfo(): string {
|
|
259
|
+
if ('Deno' in globalThis) {
|
|
260
|
+
const version = typeof Deno?.version?.deno === 'string' ? Deno?.version?.deno : '0.0.0-unknown';
|
|
261
|
+
|
|
262
|
+
return `Deno v${version}, ${os.endianness()}`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if ('Bun' in globalThis) {
|
|
266
|
+
const version = typeof Bun?.version === 'string' ? Bun?.version : '0.0.0-unknown';
|
|
267
|
+
|
|
268
|
+
return `Bun v${version}, ${os.endianness()}`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return `Node.js ${process.version}, ${os.endianness()}`;
|
|
272
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const MIN_SUPPORTED_SERVER_VERSION = '3.6';
|
|
2
|
-
export const MAX_SUPPORTED_SERVER_VERSION = '
|
|
2
|
+
export const MAX_SUPPORTED_SERVER_VERSION = '7.0';
|
|
3
3
|
export const MIN_SUPPORTED_WIRE_VERSION = 6;
|
|
4
|
-
export const MAX_SUPPORTED_WIRE_VERSION =
|
|
4
|
+
export const MAX_SUPPORTED_WIRE_VERSION = 21;
|
|
5
5
|
export const OP_REPLY = 1;
|
|
6
6
|
export const OP_UPDATE = 2001;
|
|
7
7
|
export const OP_INSERT = 2002;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Document } from '../../bson';
|
|
2
1
|
import { MongoInvalidArgumentError } from '../../error';
|
|
3
2
|
import type { ReadPreferenceLike } from '../../read_preference';
|
|
4
3
|
import { ReadPreference } from '../../read_preference';
|
|
@@ -13,9 +12,9 @@ export interface ReadPreferenceOption {
|
|
|
13
12
|
readPreference?: ReadPreferenceLike;
|
|
14
13
|
}
|
|
15
14
|
|
|
16
|
-
export function getReadPreference(
|
|
15
|
+
export function getReadPreference(options?: ReadPreferenceOption): ReadPreference {
|
|
17
16
|
// Default to command version of the readPreference
|
|
18
|
-
let readPreference =
|
|
17
|
+
let readPreference = options?.readPreference ?? ReadPreference.primary;
|
|
19
18
|
// If we have an option readPreference override the command one
|
|
20
19
|
if (options?.readPreference) {
|
|
21
20
|
readPreference = options.readPreference;
|
package/src/collection.ts
CHANGED
|
@@ -334,7 +334,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
334
334
|
filter: Filter<TSchema>,
|
|
335
335
|
update: UpdateFilter<TSchema> | Partial<TSchema>,
|
|
336
336
|
options?: UpdateOptions
|
|
337
|
-
): Promise<UpdateResult
|
|
337
|
+
): Promise<UpdateResult<TSchema>> {
|
|
338
338
|
return executeOperation(
|
|
339
339
|
this.s.db.s.client,
|
|
340
340
|
new UpdateOneOperation(
|
|
@@ -357,7 +357,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
357
357
|
filter: Filter<TSchema>,
|
|
358
358
|
replacement: WithoutId<TSchema>,
|
|
359
359
|
options?: ReplaceOptions
|
|
360
|
-
): Promise<UpdateResult | Document> {
|
|
360
|
+
): Promise<UpdateResult<TSchema> | Document> {
|
|
361
361
|
return executeOperation(
|
|
362
362
|
this.s.db.s.client,
|
|
363
363
|
new ReplaceOneOperation(
|
|
@@ -380,7 +380,7 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
380
380
|
filter: Filter<TSchema>,
|
|
381
381
|
update: UpdateFilter<TSchema>,
|
|
382
382
|
options?: UpdateOptions
|
|
383
|
-
): Promise<UpdateResult
|
|
383
|
+
): Promise<UpdateResult<TSchema>> {
|
|
384
384
|
return executeOperation(
|
|
385
385
|
this.s.db.s.client,
|
|
386
386
|
new UpdateManyOperation(
|
|
@@ -784,6 +784,9 @@ export class Collection<TSchema extends Document = Document> {
|
|
|
784
784
|
/**
|
|
785
785
|
* Get all the collection statistics.
|
|
786
786
|
*
|
|
787
|
+
* @deprecated the `collStats` operation will be removed in the next major release. Please
|
|
788
|
+
* use an aggregation pipeline with the [`$collStats`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/collStats/) stage instead
|
|
789
|
+
*
|
|
787
790
|
* @param options - Optional settings for the command
|
|
788
791
|
*/
|
|
789
792
|
async stats(options?: CollStatsOptions): Promise<CollStats> {
|
package/src/connection_string.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { URLSearchParams } from 'url';
|
|
|
6
6
|
import type { Document } from './bson';
|
|
7
7
|
import { MongoCredentials } from './cmap/auth/mongo_credentials';
|
|
8
8
|
import { AUTH_MECHS_AUTH_SRC_EXTERNAL, AuthMechanism } from './cmap/auth/providers';
|
|
9
|
+
import { makeClientMetadata } from './cmap/handshake/client_metadata';
|
|
9
10
|
import { Compressor, CompressorName } from './cmap/wire_protocol/compression';
|
|
10
11
|
import { Encrypter } from './encrypter';
|
|
11
12
|
import {
|
|
@@ -32,7 +33,7 @@ import {
|
|
|
32
33
|
emitWarningOnce,
|
|
33
34
|
HostAddress,
|
|
34
35
|
isRecord,
|
|
35
|
-
|
|
36
|
+
matchesParentDomain,
|
|
36
37
|
parseInteger,
|
|
37
38
|
setDifference
|
|
38
39
|
} from './utils';
|
|
@@ -45,21 +46,6 @@ const LB_REPLICA_SET_ERROR = 'loadBalanced option not supported with a replicaSe
|
|
|
45
46
|
const LB_DIRECT_CONNECTION_ERROR =
|
|
46
47
|
'loadBalanced option not supported when directConnection is provided';
|
|
47
48
|
|
|
48
|
-
/**
|
|
49
|
-
* Determines whether a provided address matches the provided parent domain in order
|
|
50
|
-
* to avoid certain attack vectors.
|
|
51
|
-
*
|
|
52
|
-
* @param srvAddress - The address to check against a domain
|
|
53
|
-
* @param parentDomain - The domain to check the provided address against
|
|
54
|
-
* @returns Whether the provided address matches the parent domain
|
|
55
|
-
*/
|
|
56
|
-
function matchesParentDomain(srvAddress: string, parentDomain: string): boolean {
|
|
57
|
-
const regex = /^.*?\./;
|
|
58
|
-
const srv = `.${srvAddress.replace(regex, '')}`;
|
|
59
|
-
const parent = `.${parentDomain.replace(regex, '')}`;
|
|
60
|
-
return srv.endsWith(parent);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
49
|
/**
|
|
64
50
|
* Lookup a `mongodb+srv` connection string, combine the parts and reparse it as a normal
|
|
65
51
|
* connection string.
|
|
@@ -277,7 +263,7 @@ export function parseOptions(
|
|
|
277
263
|
|
|
278
264
|
mongoOptions.hosts = isSRV ? [] : hosts.map(HostAddress.fromString);
|
|
279
265
|
|
|
280
|
-
const urlOptions = new CaseInsensitiveMap<
|
|
266
|
+
const urlOptions = new CaseInsensitiveMap<unknown[]>();
|
|
281
267
|
|
|
282
268
|
if (url.pathname !== '/' && url.pathname !== '') {
|
|
283
269
|
const dbName = decodeURIComponent(
|
|
@@ -312,7 +298,7 @@ export function parseOptions(
|
|
|
312
298
|
}
|
|
313
299
|
}
|
|
314
300
|
|
|
315
|
-
const objectOptions = new CaseInsensitiveMap(
|
|
301
|
+
const objectOptions = new CaseInsensitiveMap<unknown>(
|
|
316
302
|
Object.entries(options).filter(([, v]) => v != null)
|
|
317
303
|
);
|
|
318
304
|
|
|
@@ -324,54 +310,59 @@ export function parseOptions(
|
|
|
324
310
|
);
|
|
325
311
|
}
|
|
326
312
|
|
|
313
|
+
const uriMechanismProperties = urlOptions.get('authMechanismProperties');
|
|
314
|
+
if (uriMechanismProperties) {
|
|
315
|
+
for (const property of uriMechanismProperties) {
|
|
316
|
+
if (/(^|,)ALLOWED_HOSTS:/.test(property as string)) {
|
|
317
|
+
throw new MongoParseError(
|
|
318
|
+
'Auth mechanism property ALLOWED_HOSTS is not allowed in the connection string.'
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
327
324
|
if (objectOptions.has('loadBalanced')) {
|
|
328
325
|
throw new MongoParseError('loadBalanced is only a valid option in the URI');
|
|
329
326
|
}
|
|
330
327
|
|
|
331
328
|
// All option collection
|
|
332
329
|
|
|
333
|
-
const
|
|
330
|
+
const allProvidedOptions = new CaseInsensitiveMap<unknown[]>();
|
|
334
331
|
|
|
335
|
-
const
|
|
336
|
-
...urlOptions.keys(),
|
|
337
|
-
...objectOptions.keys(),
|
|
338
|
-
...DEFAULT_OPTIONS.keys()
|
|
339
|
-
]);
|
|
332
|
+
const allProvidedKeys = new Set<string>([...urlOptions.keys(), ...objectOptions.keys()]);
|
|
340
333
|
|
|
341
|
-
for (const key of
|
|
334
|
+
for (const key of allProvidedKeys) {
|
|
342
335
|
const values = [];
|
|
343
336
|
const objectOptionValue = objectOptions.get(key);
|
|
344
337
|
if (objectOptionValue != null) {
|
|
345
338
|
values.push(objectOptionValue);
|
|
346
339
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
const defaultOptionsValue = DEFAULT_OPTIONS.get(key);
|
|
352
|
-
if (defaultOptionsValue != null) {
|
|
353
|
-
values.push(defaultOptionsValue);
|
|
354
|
-
}
|
|
355
|
-
allOptions.set(key, values);
|
|
340
|
+
|
|
341
|
+
const urlValues = urlOptions.get(key) ?? [];
|
|
342
|
+
values.push(...urlValues);
|
|
343
|
+
allProvidedOptions.set(key, values);
|
|
356
344
|
}
|
|
357
345
|
|
|
358
|
-
if (
|
|
359
|
-
|
|
346
|
+
if (
|
|
347
|
+
allProvidedOptions.has('tlsCertificateKeyFile') &&
|
|
348
|
+
!allProvidedOptions.has('tlsCertificateFile')
|
|
349
|
+
) {
|
|
350
|
+
allProvidedOptions.set('tlsCertificateFile', allProvidedOptions.get('tlsCertificateKeyFile'));
|
|
360
351
|
}
|
|
361
352
|
|
|
362
|
-
if (
|
|
363
|
-
const tlsAndSslOpts = (
|
|
364
|
-
.concat(
|
|
353
|
+
if (allProvidedOptions.has('tls') || allProvidedOptions.has('ssl')) {
|
|
354
|
+
const tlsAndSslOpts = (allProvidedOptions.get('tls') || [])
|
|
355
|
+
.concat(allProvidedOptions.get('ssl') || [])
|
|
365
356
|
.map(getBoolean.bind(null, 'tls/ssl'));
|
|
366
357
|
if (new Set(tlsAndSslOpts).size !== 1) {
|
|
367
358
|
throw new MongoParseError('All values of tls/ssl must be the same.');
|
|
368
359
|
}
|
|
369
360
|
}
|
|
370
361
|
|
|
371
|
-
checkTLSOptions(
|
|
362
|
+
checkTLSOptions(allProvidedOptions);
|
|
372
363
|
|
|
373
364
|
const unsupportedOptions = setDifference(
|
|
374
|
-
|
|
365
|
+
allProvidedKeys,
|
|
375
366
|
Array.from(Object.keys(OPTIONS)).map(s => s.toLowerCase())
|
|
376
367
|
);
|
|
377
368
|
if (unsupportedOptions.size !== 0) {
|
|
@@ -385,9 +376,20 @@ export function parseOptions(
|
|
|
385
376
|
// Option parsing and setting
|
|
386
377
|
|
|
387
378
|
for (const [key, descriptor] of Object.entries(OPTIONS)) {
|
|
388
|
-
const values =
|
|
389
|
-
if (!values || values.length === 0)
|
|
390
|
-
|
|
379
|
+
const values = allProvidedOptions.get(key);
|
|
380
|
+
if (!values || values.length === 0) {
|
|
381
|
+
if (DEFAULT_OPTIONS.has(key)) {
|
|
382
|
+
setOption(mongoOptions, key, descriptor, [DEFAULT_OPTIONS.get(key)]);
|
|
383
|
+
}
|
|
384
|
+
} else {
|
|
385
|
+
const { deprecated } = descriptor;
|
|
386
|
+
if (deprecated) {
|
|
387
|
+
const deprecatedMsg = typeof deprecated === 'string' ? `: ${deprecated}` : '';
|
|
388
|
+
emitWarning(`${key} is a deprecated option${deprecatedMsg}`);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
setOption(mongoOptions, key, descriptor, values);
|
|
392
|
+
}
|
|
391
393
|
}
|
|
392
394
|
|
|
393
395
|
if (mongoOptions.credentials) {
|
|
@@ -397,7 +399,7 @@ export function parseOptions(
|
|
|
397
399
|
const isOidc = mongoOptions.credentials.mechanism === AuthMechanism.MONGODB_OIDC;
|
|
398
400
|
if (
|
|
399
401
|
(isGssapi || isX509) &&
|
|
400
|
-
|
|
402
|
+
allProvidedOptions.has('authSource') &&
|
|
401
403
|
mongoOptions.credentials.source !== '$external'
|
|
402
404
|
) {
|
|
403
405
|
// If authSource was explicitly given and its incorrect, we error
|
|
@@ -409,7 +411,7 @@ export function parseOptions(
|
|
|
409
411
|
if (
|
|
410
412
|
!(isGssapi || isX509 || isAws || isOidc) &&
|
|
411
413
|
mongoOptions.dbName &&
|
|
412
|
-
!
|
|
414
|
+
!allProvidedOptions.has('authSource')
|
|
413
415
|
) {
|
|
414
416
|
// inherit the dbName unless GSSAPI or X509, then silently ignore dbName
|
|
415
417
|
// and there was no specific authSource given
|
|
@@ -585,14 +587,9 @@ function setOption(
|
|
|
585
587
|
descriptor: OptionDescriptor,
|
|
586
588
|
values: unknown[]
|
|
587
589
|
) {
|
|
588
|
-
const { target, type, transform
|
|
590
|
+
const { target, type, transform } = descriptor;
|
|
589
591
|
const name = target ?? key;
|
|
590
592
|
|
|
591
|
-
if (deprecated) {
|
|
592
|
-
const deprecatedMsg = typeof deprecated === 'string' ? `: ${deprecated}` : '';
|
|
593
|
-
emitWarning(`${key} is a deprecated option${deprecatedMsg}`);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
593
|
switch (type) {
|
|
597
594
|
case 'boolean':
|
|
598
595
|
mongoOptions[name] = getBoolean(name, values[0]);
|
|
@@ -866,11 +863,13 @@ export const OPTIONS = {
|
|
|
866
863
|
},
|
|
867
864
|
keepAlive: {
|
|
868
865
|
default: true,
|
|
869
|
-
type: 'boolean'
|
|
866
|
+
type: 'boolean',
|
|
867
|
+
deprecated: 'Will not be able to turn off in the future.'
|
|
870
868
|
},
|
|
871
869
|
keepAliveInitialDelay: {
|
|
872
870
|
default: 120000,
|
|
873
|
-
type: 'uint'
|
|
871
|
+
type: 'uint',
|
|
872
|
+
deprecated: 'Will not be configurable in the future.'
|
|
874
873
|
},
|
|
875
874
|
loadBalanced: {
|
|
876
875
|
default: false,
|
|
@@ -1292,5 +1291,6 @@ export const DEFAULT_OPTIONS = new CaseInsensitiveMap(
|
|
|
1292
1291
|
*/
|
|
1293
1292
|
export const FEATURE_FLAGS = new Set([
|
|
1294
1293
|
Symbol.for('@@mdb.skipPingOnConnect'),
|
|
1295
|
-
Symbol.for('@@mdb.enableMongoLogger')
|
|
1294
|
+
Symbol.for('@@mdb.enableMongoLogger'),
|
|
1295
|
+
Symbol.for('@@mdb.internalLoggerConfig')
|
|
1296
1296
|
]);
|
package/src/constants.ts
CHANGED
|
@@ -23,16 +23,27 @@ export const SERVER_DESCRIPTION_CHANGED = 'serverDescriptionChanged' as const;
|
|
|
23
23
|
export const TOPOLOGY_OPENING = 'topologyOpening' as const;
|
|
24
24
|
export const TOPOLOGY_CLOSED = 'topologyClosed' as const;
|
|
25
25
|
export const TOPOLOGY_DESCRIPTION_CHANGED = 'topologyDescriptionChanged' as const;
|
|
26
|
+
/** @internal */
|
|
26
27
|
export const CONNECTION_POOL_CREATED = 'connectionPoolCreated' as const;
|
|
28
|
+
/** @internal */
|
|
27
29
|
export const CONNECTION_POOL_CLOSED = 'connectionPoolClosed' as const;
|
|
30
|
+
/** @internal */
|
|
28
31
|
export const CONNECTION_POOL_CLEARED = 'connectionPoolCleared' as const;
|
|
32
|
+
/** @internal */
|
|
29
33
|
export const CONNECTION_POOL_READY = 'connectionPoolReady' as const;
|
|
34
|
+
/** @internal */
|
|
30
35
|
export const CONNECTION_CREATED = 'connectionCreated' as const;
|
|
36
|
+
/** @internal */
|
|
31
37
|
export const CONNECTION_READY = 'connectionReady' as const;
|
|
38
|
+
/** @internal */
|
|
32
39
|
export const CONNECTION_CLOSED = 'connectionClosed' as const;
|
|
40
|
+
/** @internal */
|
|
33
41
|
export const CONNECTION_CHECK_OUT_STARTED = 'connectionCheckOutStarted' as const;
|
|
42
|
+
/** @internal */
|
|
34
43
|
export const CONNECTION_CHECK_OUT_FAILED = 'connectionCheckOutFailed' as const;
|
|
44
|
+
/** @internal */
|
|
35
45
|
export const CONNECTION_CHECKED_OUT = 'connectionCheckedOut' as const;
|
|
46
|
+
/** @internal */
|
|
36
47
|
export const CONNECTION_CHECKED_IN = 'connectionCheckedIn' as const;
|
|
37
48
|
export const CLUSTER_TIME_RECEIVED = 'clusterTimeReceived' as const;
|
|
38
49
|
export const COMMAND_STARTED = 'commandStarted' as const;
|
|
@@ -397,6 +397,7 @@ export abstract class AbstractCursor<
|
|
|
397
397
|
* If the iterator returns `false`, iteration will stop.
|
|
398
398
|
*
|
|
399
399
|
* @param iterator - The iteration callback.
|
|
400
|
+
* @deprecated - Will be removed in a future release. Use for await...of instead.
|
|
400
401
|
*/
|
|
401
402
|
async forEach(iterator: (doc: TSchema) => boolean | void): Promise<void> {
|
|
402
403
|
if (typeof iterator !== 'function') {
|
package/src/db.ts
CHANGED
|
@@ -232,6 +232,22 @@ export class Db {
|
|
|
232
232
|
* @remarks
|
|
233
233
|
* This command does not inherit options from the MongoClient.
|
|
234
234
|
*
|
|
235
|
+
* The driver will ensure the following fields are attached to the command sent to the server:
|
|
236
|
+
* - `lsid` - sourced from an implicit session or options.session
|
|
237
|
+
* - `$readPreference` - defaults to primary or can be configured by options.readPreference
|
|
238
|
+
* - `$db` - sourced from the name of this database
|
|
239
|
+
*
|
|
240
|
+
* If the client has a serverApi setting:
|
|
241
|
+
* - `apiVersion`
|
|
242
|
+
* - `apiStrict`
|
|
243
|
+
* - `apiDeprecationErrors`
|
|
244
|
+
*
|
|
245
|
+
* When in a transaction:
|
|
246
|
+
* - `readConcern` - sourced from readConcern set on the TransactionOptions
|
|
247
|
+
* - `writeConcern` - sourced from writeConcern set on the TransactionOptions
|
|
248
|
+
*
|
|
249
|
+
* Attaching any of the above fields to the command will have no effect as the driver will overwrite the value.
|
|
250
|
+
*
|
|
235
251
|
* @param command - The command to run
|
|
236
252
|
* @param options - Optional settings for the command
|
|
237
253
|
*/
|
|
@@ -405,6 +421,8 @@ export class Db {
|
|
|
405
421
|
* @param username - The username for the new user
|
|
406
422
|
* @param passwordOrOptions - An optional password for the new user, or the options for the command
|
|
407
423
|
* @param options - Optional settings for the command
|
|
424
|
+
* @deprecated Use the createUser command in `db.command()` instead.
|
|
425
|
+
* @see https://www.mongodb.com/docs/manual/reference/command/createUser/
|
|
408
426
|
*/
|
|
409
427
|
async addUser(
|
|
410
428
|
username: string,
|
package/src/index.ts
CHANGED
|
@@ -204,10 +204,11 @@ export type {
|
|
|
204
204
|
MongoCredentialsOptions
|
|
205
205
|
} from './cmap/auth/mongo_credentials';
|
|
206
206
|
export type {
|
|
207
|
-
|
|
207
|
+
IdPServerInfo,
|
|
208
|
+
IdPServerResponse,
|
|
209
|
+
OIDCCallbackContext,
|
|
208
210
|
OIDCRefreshFunction,
|
|
209
|
-
OIDCRequestFunction
|
|
210
|
-
OIDCRequestTokenResult
|
|
211
|
+
OIDCRequestFunction
|
|
211
212
|
} from './cmap/auth/mongodb_oidc';
|
|
212
213
|
export type {
|
|
213
214
|
BinMsg,
|
|
@@ -238,6 +239,7 @@ export type {
|
|
|
238
239
|
WaitQueueMember,
|
|
239
240
|
WithConnectionCallback
|
|
240
241
|
} from './cmap/connection_pool';
|
|
242
|
+
export type { ClientMetadata, ClientMetadataOptions } from './cmap/handshake/client_metadata';
|
|
241
243
|
export type {
|
|
242
244
|
MessageStream,
|
|
243
245
|
MessageStreamOptions,
|
|
@@ -247,7 +249,20 @@ export type { ConnectionPoolMetrics } from './cmap/metrics';
|
|
|
247
249
|
export type { StreamDescription, StreamDescriptionOptions } from './cmap/stream_description';
|
|
248
250
|
export type { CompressorName } from './cmap/wire_protocol/compression';
|
|
249
251
|
export type { CollectionOptions, CollectionPrivate, ModifyResult } from './collection';
|
|
250
|
-
export type {
|
|
252
|
+
export type {
|
|
253
|
+
CONNECTION_CHECK_OUT_FAILED,
|
|
254
|
+
CONNECTION_CHECK_OUT_STARTED,
|
|
255
|
+
CONNECTION_CHECKED_IN,
|
|
256
|
+
CONNECTION_CHECKED_OUT,
|
|
257
|
+
CONNECTION_CLOSED,
|
|
258
|
+
CONNECTION_CREATED,
|
|
259
|
+
CONNECTION_POOL_CLEARED,
|
|
260
|
+
CONNECTION_POOL_CLOSED,
|
|
261
|
+
CONNECTION_POOL_CREATED,
|
|
262
|
+
CONNECTION_POOL_READY,
|
|
263
|
+
CONNECTION_READY,
|
|
264
|
+
MONGO_CLIENT_EVENTS
|
|
265
|
+
} from './constants';
|
|
251
266
|
export type {
|
|
252
267
|
AbstractCursorEvents,
|
|
253
268
|
AbstractCursorOptions,
|
|
@@ -289,6 +304,11 @@ export type {
|
|
|
289
304
|
WithSessionCallback
|
|
290
305
|
} from './mongo_client';
|
|
291
306
|
export type {
|
|
307
|
+
Log,
|
|
308
|
+
LogConvertible,
|
|
309
|
+
Loggable,
|
|
310
|
+
LoggableEvent,
|
|
311
|
+
MongoDBLogWritable,
|
|
292
312
|
MongoLoggableComponent,
|
|
293
313
|
MongoLogger,
|
|
294
314
|
MongoLoggerEnvOptions,
|
|
@@ -463,8 +483,6 @@ export type { Transaction, TransactionOptions, TxnState } from './transactions';
|
|
|
463
483
|
export type {
|
|
464
484
|
BufferPool,
|
|
465
485
|
Callback,
|
|
466
|
-
ClientMetadata,
|
|
467
|
-
ClientMetadataOptions,
|
|
468
486
|
EventEmitterWithState,
|
|
469
487
|
HostAddress,
|
|
470
488
|
List,
|