mongodb 5.2.0 → 5.3.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 +2 -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/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.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/connection_string.js +40 -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 +2 -0
- package/lib/db.js.map +1 -1
- package/lib/mongo_client.js +1 -0
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_logger.js +224 -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/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 +33 -35
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +139 -23
- package/package.json +2 -2
- package/src/admin.ts +2 -0
- package/src/bulk/common.ts +28 -7
- package/src/cmap/command_monitoring_events.ts +13 -1
- package/src/cmap/connect.ts +3 -1
- package/src/cmap/connection.ts +3 -1
- 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/collection.ts +3 -3
- package/src/connection_string.ts +44 -55
- package/src/constants.ts +11 -0
- package/src/cursor/abstract_cursor.ts +1 -0
- package/src/db.ts +2 -0
- package/src/index.ts +20 -3
- package/src/mongo_client.ts +25 -4
- package/src/mongo_logger.ts +326 -43
- package/src/operations/add_user.ts +8 -2
- package/src/operations/find.ts +0 -10
- 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 +37 -73
package/src/bulk/common.ts
CHANGED
|
@@ -212,37 +212,58 @@ export class BulkWriteResult {
|
|
|
212
212
|
return this.result.ok;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
/**
|
|
215
|
+
/**
|
|
216
|
+
* The number of inserted documents
|
|
217
|
+
* @deprecated Use insertedCount instead.
|
|
218
|
+
*/
|
|
216
219
|
get nInserted(): number {
|
|
217
220
|
return this.result.nInserted;
|
|
218
221
|
}
|
|
219
222
|
|
|
220
|
-
/**
|
|
223
|
+
/**
|
|
224
|
+
* Number of upserted documents
|
|
225
|
+
* @deprecated User upsertedCount instead.
|
|
226
|
+
*/
|
|
221
227
|
get nUpserted(): number {
|
|
222
228
|
return this.result.nUpserted;
|
|
223
229
|
}
|
|
224
230
|
|
|
225
|
-
/**
|
|
231
|
+
/**
|
|
232
|
+
* Number of matched documents
|
|
233
|
+
* @deprecated Use matchedCount instead.
|
|
234
|
+
*/
|
|
226
235
|
get nMatched(): number {
|
|
227
236
|
return this.result.nMatched;
|
|
228
237
|
}
|
|
229
238
|
|
|
230
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
* Number of documents updated physically on disk
|
|
241
|
+
* @deprecated Use modifiedCount instead.
|
|
242
|
+
*/
|
|
231
243
|
get nModified(): number {
|
|
232
244
|
return this.result.nModified;
|
|
233
245
|
}
|
|
234
246
|
|
|
235
|
-
/**
|
|
247
|
+
/**
|
|
248
|
+
* Number of removed documents
|
|
249
|
+
* @deprecated Use deletedCount instead.
|
|
250
|
+
*/
|
|
236
251
|
get nRemoved(): number {
|
|
237
252
|
return this.result.nRemoved;
|
|
238
253
|
}
|
|
239
254
|
|
|
240
|
-
/**
|
|
255
|
+
/**
|
|
256
|
+
* Returns an array of all inserted ids
|
|
257
|
+
* @deprecated Use insertedIds instead.
|
|
258
|
+
*/
|
|
241
259
|
getInsertedIds(): Document[] {
|
|
242
260
|
return this.result.insertedIds;
|
|
243
261
|
}
|
|
244
262
|
|
|
245
|
-
/**
|
|
263
|
+
/**
|
|
264
|
+
* Returns an array of all upserted ids
|
|
265
|
+
* @deprecated Use upsertedIds instead.
|
|
266
|
+
*/
|
|
246
267
|
getUpsertedIds(): Document[] {
|
|
247
268
|
return this.result.upserted;
|
|
248
269
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { Document, ObjectId } from '../bson';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
COMMAND_FAILED,
|
|
4
|
+
COMMAND_STARTED,
|
|
5
|
+
COMMAND_SUCCEEDED,
|
|
6
|
+
LEGACY_HELLO_COMMAND,
|
|
7
|
+
LEGACY_HELLO_COMMAND_CAMEL_CASE
|
|
8
|
+
} from '../constants';
|
|
3
9
|
import { calculateDurationInMs, deepCopy } from '../utils';
|
|
4
10
|
import { Msg, WriteProtocolMessageType } from './commands';
|
|
5
11
|
import type { Connection } from './connection';
|
|
@@ -18,6 +24,8 @@ export class CommandStartedEvent {
|
|
|
18
24
|
address: string;
|
|
19
25
|
connectionId?: string | number;
|
|
20
26
|
serviceId?: ObjectId;
|
|
27
|
+
/** @internal */
|
|
28
|
+
name = COMMAND_STARTED;
|
|
21
29
|
|
|
22
30
|
/**
|
|
23
31
|
* Create a started event
|
|
@@ -65,6 +73,8 @@ export class CommandSucceededEvent {
|
|
|
65
73
|
commandName: string;
|
|
66
74
|
reply: unknown;
|
|
67
75
|
serviceId?: ObjectId;
|
|
76
|
+
/** @internal */
|
|
77
|
+
name = COMMAND_SUCCEEDED;
|
|
68
78
|
|
|
69
79
|
/**
|
|
70
80
|
* Create a succeeded event
|
|
@@ -113,6 +123,8 @@ export class CommandFailedEvent {
|
|
|
113
123
|
commandName: string;
|
|
114
124
|
failure: Error;
|
|
115
125
|
serviceId?: ObjectId;
|
|
126
|
+
/** @internal */
|
|
127
|
+
name = COMMAND_FAILED;
|
|
116
128
|
|
|
117
129
|
/**
|
|
118
130
|
* Create a failure event
|
package/src/cmap/connect.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
MongoRuntimeError,
|
|
18
18
|
needsRetryableWriteLabel
|
|
19
19
|
} from '../error';
|
|
20
|
-
import { Callback,
|
|
20
|
+
import { Callback, HostAddress, ns } from '../utils';
|
|
21
21
|
import { AuthContext, AuthProvider } from './auth/auth_provider';
|
|
22
22
|
import { GSSAPI } from './auth/gssapi';
|
|
23
23
|
import { MongoCR } from './auth/mongocr';
|
|
@@ -28,6 +28,7 @@ import { AuthMechanism } from './auth/providers';
|
|
|
28
28
|
import { ScramSHA1, ScramSHA256 } from './auth/scram';
|
|
29
29
|
import { X509 } from './auth/x509';
|
|
30
30
|
import { CommandOptions, Connection, ConnectionOptions, CryptoConnection } from './connection';
|
|
31
|
+
import type { ClientMetadata } from './handshake/client_metadata';
|
|
31
32
|
import {
|
|
32
33
|
MAX_SUPPORTED_SERVER_VERSION,
|
|
33
34
|
MAX_SUPPORTED_WIRE_VERSION,
|
|
@@ -400,6 +401,7 @@ function makeConnection(options: MakeConnectionOptions, _callback: Callback<Stre
|
|
|
400
401
|
|
|
401
402
|
if ('authorizationError' in socket) {
|
|
402
403
|
if (socket.authorizationError && rejectUnauthorized) {
|
|
404
|
+
// TODO(NODE-5192): wrap this with a MongoError subclass
|
|
403
405
|
return callback(socket.authorizationError);
|
|
404
406
|
}
|
|
405
407
|
}
|
package/src/cmap/connection.ts
CHANGED
|
@@ -29,7 +29,6 @@ import { applySession, ClientSession, updateSessionFromResponse } from '../sessi
|
|
|
29
29
|
import {
|
|
30
30
|
calculateDurationInMs,
|
|
31
31
|
Callback,
|
|
32
|
-
ClientMetadata,
|
|
33
32
|
HostAddress,
|
|
34
33
|
maxWireVersion,
|
|
35
34
|
MongoDBNamespace,
|
|
@@ -46,6 +45,7 @@ import {
|
|
|
46
45
|
} from './command_monitoring_events';
|
|
47
46
|
import { BinMsg, Msg, Query, Response, WriteProtocolMessageType } from './commands';
|
|
48
47
|
import type { Stream } from './connect';
|
|
48
|
+
import type { ClientMetadata } from './handshake/client_metadata';
|
|
49
49
|
import { MessageStream, OperationDescription } from './message_stream';
|
|
50
50
|
import { StreamDescription, StreamDescriptionOptions } from './stream_description';
|
|
51
51
|
import { getReadPreference, isSharded } from './wire_protocol/shared';
|
|
@@ -122,7 +122,9 @@ export interface ConnectionOptions
|
|
|
122
122
|
credentials?: MongoCredentials;
|
|
123
123
|
connectTimeoutMS?: number;
|
|
124
124
|
tls: boolean;
|
|
125
|
+
/** @deprecated - Will not be able to turn off in the future. */
|
|
125
126
|
keepAlive?: boolean;
|
|
127
|
+
/** @deprecated - Will not be configurable in the future. */
|
|
126
128
|
keepAliveInitialDelay?: number;
|
|
127
129
|
noDelay?: boolean;
|
|
128
130
|
socketTimeoutMS?: number;
|
|
@@ -641,7 +641,10 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
641
641
|
}
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
-
private destroyConnection(
|
|
644
|
+
private destroyConnection(
|
|
645
|
+
connection: Connection,
|
|
646
|
+
reason: 'error' | 'idle' | 'stale' | 'poolClosed'
|
|
647
|
+
) {
|
|
645
648
|
this.emit(
|
|
646
649
|
ConnectionPool.CONNECTION_CLOSED,
|
|
647
650
|
new ConnectionClosedEvent(this, connection, reason)
|
|
@@ -701,7 +704,13 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
701
704
|
this[kPending]--;
|
|
702
705
|
this.emit(
|
|
703
706
|
ConnectionPool.CONNECTION_CLOSED,
|
|
704
|
-
new ConnectionClosedEvent(
|
|
707
|
+
new ConnectionClosedEvent(
|
|
708
|
+
this,
|
|
709
|
+
{ id: connectOptions.id, serviceId: undefined },
|
|
710
|
+
'error',
|
|
711
|
+
// TODO(NODE-5192): Remove this cast
|
|
712
|
+
err as MongoError
|
|
713
|
+
)
|
|
705
714
|
);
|
|
706
715
|
if (err instanceof MongoNetworkError || err instanceof MongoServerError) {
|
|
707
716
|
err.connectionGeneration = connectOptions.generation;
|
|
@@ -812,7 +821,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
812
821
|
const error = this.closed ? new PoolClosedError(this) : new PoolClearedError(this);
|
|
813
822
|
this.emit(
|
|
814
823
|
ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
|
|
815
|
-
new ConnectionCheckOutFailedEvent(this, reason)
|
|
824
|
+
new ConnectionCheckOutFailedEvent(this, reason, error)
|
|
816
825
|
);
|
|
817
826
|
if (waitQueueMember.timer) {
|
|
818
827
|
clearTimeout(waitQueueMember.timer);
|
|
@@ -865,7 +874,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
865
874
|
if (err) {
|
|
866
875
|
this.emit(
|
|
867
876
|
ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
|
|
868
|
-
|
|
877
|
+
// TODO(NODE-5192): Remove this cast
|
|
878
|
+
new ConnectionCheckOutFailedEvent(this, 'connectionError', err as MongoError)
|
|
869
879
|
);
|
|
870
880
|
} else if (connection) {
|
|
871
881
|
this[kCheckedOut].add(connection);
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import type { ObjectId } from '../bson';
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
CONNECTION_CHECK_OUT_FAILED,
|
|
4
|
+
CONNECTION_CHECK_OUT_STARTED,
|
|
5
|
+
CONNECTION_CHECKED_IN,
|
|
6
|
+
CONNECTION_CHECKED_OUT,
|
|
7
|
+
CONNECTION_CLOSED,
|
|
8
|
+
CONNECTION_CREATED,
|
|
9
|
+
CONNECTION_POOL_CLEARED,
|
|
10
|
+
CONNECTION_POOL_CLOSED,
|
|
11
|
+
CONNECTION_POOL_CREATED,
|
|
12
|
+
CONNECTION_POOL_READY,
|
|
13
|
+
CONNECTION_READY
|
|
14
|
+
} from '../constants';
|
|
15
|
+
import type { MongoError } from '../error';
|
|
3
16
|
import type { Connection } from './connection';
|
|
4
17
|
import type { ConnectionPool, ConnectionPoolOptions } from './connection_pool';
|
|
5
18
|
|
|
@@ -8,11 +21,24 @@ import type { ConnectionPool, ConnectionPoolOptions } from './connection_pool';
|
|
|
8
21
|
* @public
|
|
9
22
|
* @category Event
|
|
10
23
|
*/
|
|
11
|
-
export class ConnectionPoolMonitoringEvent {
|
|
24
|
+
export abstract class ConnectionPoolMonitoringEvent {
|
|
12
25
|
/** A timestamp when the event was created */
|
|
13
26
|
time: Date;
|
|
14
27
|
/** The address (host/port pair) of the pool */
|
|
15
28
|
address: string;
|
|
29
|
+
/** @internal */
|
|
30
|
+
abstract name:
|
|
31
|
+
| typeof CONNECTION_CHECK_OUT_FAILED
|
|
32
|
+
| typeof CONNECTION_CHECK_OUT_STARTED
|
|
33
|
+
| typeof CONNECTION_CHECKED_IN
|
|
34
|
+
| typeof CONNECTION_CHECKED_OUT
|
|
35
|
+
| typeof CONNECTION_CLOSED
|
|
36
|
+
| typeof CONNECTION_CREATED
|
|
37
|
+
| typeof CONNECTION_POOL_CLEARED
|
|
38
|
+
| typeof CONNECTION_POOL_CLOSED
|
|
39
|
+
| typeof CONNECTION_POOL_CREATED
|
|
40
|
+
| typeof CONNECTION_POOL_READY
|
|
41
|
+
| typeof CONNECTION_READY;
|
|
16
42
|
|
|
17
43
|
/** @internal */
|
|
18
44
|
constructor(pool: ConnectionPool) {
|
|
@@ -29,6 +55,8 @@ export class ConnectionPoolMonitoringEvent {
|
|
|
29
55
|
export class ConnectionPoolCreatedEvent extends ConnectionPoolMonitoringEvent {
|
|
30
56
|
/** The options used to create this connection pool */
|
|
31
57
|
options?: ConnectionPoolOptions;
|
|
58
|
+
/** @internal */
|
|
59
|
+
name = CONNECTION_POOL_CREATED;
|
|
32
60
|
|
|
33
61
|
/** @internal */
|
|
34
62
|
constructor(pool: ConnectionPool) {
|
|
@@ -43,6 +71,9 @@ export class ConnectionPoolCreatedEvent extends ConnectionPoolMonitoringEvent {
|
|
|
43
71
|
* @category Event
|
|
44
72
|
*/
|
|
45
73
|
export class ConnectionPoolReadyEvent extends ConnectionPoolMonitoringEvent {
|
|
74
|
+
/** @internal */
|
|
75
|
+
name = CONNECTION_POOL_READY;
|
|
76
|
+
|
|
46
77
|
/** @internal */
|
|
47
78
|
constructor(pool: ConnectionPool) {
|
|
48
79
|
super(pool);
|
|
@@ -55,6 +86,9 @@ export class ConnectionPoolReadyEvent extends ConnectionPoolMonitoringEvent {
|
|
|
55
86
|
* @category Event
|
|
56
87
|
*/
|
|
57
88
|
export class ConnectionPoolClosedEvent extends ConnectionPoolMonitoringEvent {
|
|
89
|
+
/** @internal */
|
|
90
|
+
name = CONNECTION_POOL_CLOSED;
|
|
91
|
+
|
|
58
92
|
/** @internal */
|
|
59
93
|
constructor(pool: ConnectionPool) {
|
|
60
94
|
super(pool);
|
|
@@ -69,6 +103,8 @@ export class ConnectionPoolClosedEvent extends ConnectionPoolMonitoringEvent {
|
|
|
69
103
|
export class ConnectionCreatedEvent extends ConnectionPoolMonitoringEvent {
|
|
70
104
|
/** A monotonically increasing, per-pool id for the newly created connection */
|
|
71
105
|
connectionId: number | '<monitor>';
|
|
106
|
+
/** @internal */
|
|
107
|
+
name = CONNECTION_CREATED;
|
|
72
108
|
|
|
73
109
|
/** @internal */
|
|
74
110
|
constructor(pool: ConnectionPool, connection: { id: number | '<monitor>' }) {
|
|
@@ -85,6 +121,8 @@ export class ConnectionCreatedEvent extends ConnectionPoolMonitoringEvent {
|
|
|
85
121
|
export class ConnectionReadyEvent extends ConnectionPoolMonitoringEvent {
|
|
86
122
|
/** The id of the connection */
|
|
87
123
|
connectionId: number | '<monitor>';
|
|
124
|
+
/** @internal */
|
|
125
|
+
name = CONNECTION_READY;
|
|
88
126
|
|
|
89
127
|
/** @internal */
|
|
90
128
|
constructor(pool: ConnectionPool, connection: Connection) {
|
|
@@ -104,17 +142,23 @@ export class ConnectionClosedEvent extends ConnectionPoolMonitoringEvent {
|
|
|
104
142
|
/** The reason the connection was closed */
|
|
105
143
|
reason: string;
|
|
106
144
|
serviceId?: ObjectId;
|
|
145
|
+
/** @internal */
|
|
146
|
+
name = CONNECTION_CLOSED;
|
|
147
|
+
/** @internal */
|
|
148
|
+
error: MongoError | null;
|
|
107
149
|
|
|
108
150
|
/** @internal */
|
|
109
151
|
constructor(
|
|
110
152
|
pool: ConnectionPool,
|
|
111
153
|
connection: Pick<Connection, 'id' | 'serviceId'>,
|
|
112
|
-
reason:
|
|
154
|
+
reason: 'idle' | 'stale' | 'poolClosed' | 'error',
|
|
155
|
+
error?: MongoError
|
|
113
156
|
) {
|
|
114
157
|
super(pool);
|
|
115
158
|
this.connectionId = connection.id;
|
|
116
|
-
this.reason = reason
|
|
159
|
+
this.reason = reason;
|
|
117
160
|
this.serviceId = connection.serviceId;
|
|
161
|
+
this.error = error ?? null;
|
|
118
162
|
}
|
|
119
163
|
}
|
|
120
164
|
|
|
@@ -124,6 +168,9 @@ export class ConnectionClosedEvent extends ConnectionPoolMonitoringEvent {
|
|
|
124
168
|
* @category Event
|
|
125
169
|
*/
|
|
126
170
|
export class ConnectionCheckOutStartedEvent extends ConnectionPoolMonitoringEvent {
|
|
171
|
+
/** @internal */
|
|
172
|
+
name = CONNECTION_CHECK_OUT_STARTED;
|
|
173
|
+
|
|
127
174
|
/** @internal */
|
|
128
175
|
constructor(pool: ConnectionPool) {
|
|
129
176
|
super(pool);
|
|
@@ -137,12 +184,21 @@ export class ConnectionCheckOutStartedEvent extends ConnectionPoolMonitoringEven
|
|
|
137
184
|
*/
|
|
138
185
|
export class ConnectionCheckOutFailedEvent extends ConnectionPoolMonitoringEvent {
|
|
139
186
|
/** The reason the attempt to check out failed */
|
|
140
|
-
reason:
|
|
187
|
+
reason: string;
|
|
188
|
+
/** @internal */
|
|
189
|
+
error?: MongoError;
|
|
190
|
+
/** @internal */
|
|
191
|
+
name = CONNECTION_CHECK_OUT_FAILED;
|
|
141
192
|
|
|
142
193
|
/** @internal */
|
|
143
|
-
constructor(
|
|
194
|
+
constructor(
|
|
195
|
+
pool: ConnectionPool,
|
|
196
|
+
reason: 'poolClosed' | 'timeout' | 'connectionError',
|
|
197
|
+
error?: MongoError
|
|
198
|
+
) {
|
|
144
199
|
super(pool);
|
|
145
200
|
this.reason = reason;
|
|
201
|
+
this.error = error;
|
|
146
202
|
}
|
|
147
203
|
}
|
|
148
204
|
|
|
@@ -154,6 +210,8 @@ export class ConnectionCheckOutFailedEvent extends ConnectionPoolMonitoringEvent
|
|
|
154
210
|
export class ConnectionCheckedOutEvent extends ConnectionPoolMonitoringEvent {
|
|
155
211
|
/** The id of the connection */
|
|
156
212
|
connectionId: number | '<monitor>';
|
|
213
|
+
/** @internal */
|
|
214
|
+
name = CONNECTION_CHECKED_OUT;
|
|
157
215
|
|
|
158
216
|
/** @internal */
|
|
159
217
|
constructor(pool: ConnectionPool, connection: Connection) {
|
|
@@ -170,6 +228,8 @@ export class ConnectionCheckedOutEvent extends ConnectionPoolMonitoringEvent {
|
|
|
170
228
|
export class ConnectionCheckedInEvent extends ConnectionPoolMonitoringEvent {
|
|
171
229
|
/** The id of the connection */
|
|
172
230
|
connectionId: number | '<monitor>';
|
|
231
|
+
/** @internal */
|
|
232
|
+
name = CONNECTION_CHECKED_IN;
|
|
173
233
|
|
|
174
234
|
/** @internal */
|
|
175
235
|
constructor(pool: ConnectionPool, connection: Connection) {
|
|
@@ -188,6 +248,8 @@ export class ConnectionPoolClearedEvent extends ConnectionPoolMonitoringEvent {
|
|
|
188
248
|
serviceId?: ObjectId;
|
|
189
249
|
|
|
190
250
|
interruptInUseConnections?: boolean;
|
|
251
|
+
/** @internal */
|
|
252
|
+
name = CONNECTION_POOL_CLEARED;
|
|
191
253
|
|
|
192
254
|
/** @internal */
|
|
193
255
|
constructor(
|
|
@@ -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
|
+
}
|
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(
|