bson 4.2.2 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/HISTORY.md +44 -0
  2. package/bower.json +1 -1
  3. package/bson.d.ts +77 -6
  4. package/dist/bson.browser.esm.js +2116 -1292
  5. package/dist/bson.browser.esm.js.map +1 -1
  6. package/dist/bson.browser.umd.js +2172 -1347
  7. package/dist/bson.browser.umd.js.map +1 -1
  8. package/dist/bson.bundle.js +2174 -1347
  9. package/dist/bson.bundle.js.map +1 -1
  10. package/dist/bson.esm.js +2061 -1241
  11. package/dist/bson.esm.js.map +1 -1
  12. package/lib/binary.js +71 -60
  13. package/lib/binary.js.map +1 -1
  14. package/lib/bson.js +60 -52
  15. package/lib/bson.js.map +1 -1
  16. package/lib/code.js +18 -15
  17. package/lib/code.js.map +1 -1
  18. package/lib/db_ref.js +40 -30
  19. package/lib/db_ref.js.map +1 -1
  20. package/lib/decimal128.js +135 -124
  21. package/lib/decimal128.js.map +1 -1
  22. package/lib/double.js +24 -21
  23. package/lib/double.js.map +1 -1
  24. package/lib/ensure_buffer.js +4 -7
  25. package/lib/ensure_buffer.js.map +1 -1
  26. package/lib/extended_json.js +113 -71
  27. package/lib/extended_json.js.map +1 -1
  28. package/lib/float_parser.js +21 -21
  29. package/lib/float_parser.js.map +1 -1
  30. package/lib/int_32.js +19 -16
  31. package/lib/int_32.js.map +1 -1
  32. package/lib/long.js +248 -230
  33. package/lib/long.js.map +1 -1
  34. package/lib/map.js +54 -45
  35. package/lib/map.js.map +1 -1
  36. package/lib/max_key.js +16 -11
  37. package/lib/max_key.js.map +1 -1
  38. package/lib/min_key.js +16 -11
  39. package/lib/min_key.js.map +1 -1
  40. package/lib/objectid.js +96 -93
  41. package/lib/objectid.js.map +1 -1
  42. package/lib/parser/calculate_size.js +17 -15
  43. package/lib/parser/calculate_size.js.map +1 -1
  44. package/lib/parser/deserializer.js +135 -123
  45. package/lib/parser/deserializer.js.map +1 -1
  46. package/lib/parser/serializer.js +108 -88
  47. package/lib/parser/serializer.js.map +1 -1
  48. package/lib/parser/utils.js +47 -25
  49. package/lib/parser/utils.js.map +1 -1
  50. package/lib/regexp.js +16 -15
  51. package/lib/regexp.js.map +1 -1
  52. package/lib/symbol.js +21 -18
  53. package/lib/symbol.js.map +1 -1
  54. package/lib/timestamp.js +50 -27
  55. package/lib/timestamp.js.map +1 -1
  56. package/lib/uuid.js +173 -42
  57. package/lib/uuid.js.map +1 -1
  58. package/lib/uuid_utils.js +34 -0
  59. package/lib/uuid_utils.js.map +1 -0
  60. package/lib/validate_utf8.js +12 -12
  61. package/lib/validate_utf8.js.map +1 -1
  62. package/package.json +5 -4
  63. package/src/binary.ts +20 -6
  64. package/src/bson.ts +3 -0
  65. package/src/code.ts +6 -2
  66. package/src/db_ref.ts +14 -5
  67. package/src/decimal128.ts +14 -5
  68. package/src/double.ts +4 -2
  69. package/src/ensure_buffer.ts +7 -7
  70. package/src/extended_json.ts +64 -16
  71. package/src/int_32.ts +4 -2
  72. package/src/long.ts +22 -8
  73. package/src/max_key.ts +5 -1
  74. package/src/min_key.ts +5 -1
  75. package/src/objectid.ts +15 -20
  76. package/src/parser/calculate_size.ts +8 -11
  77. package/src/parser/deserializer.ts +46 -36
  78. package/src/parser/serializer.ts +13 -12
  79. package/src/parser/utils.ts +49 -17
  80. package/src/regexp.ts +5 -5
  81. package/src/symbol.ts +4 -2
  82. package/src/timestamp.ts +6 -1
  83. package/src/uuid.ts +192 -40
  84. package/src/uuid_utils.ts +31 -0
@@ -1,7 +1,7 @@
1
1
  import { Binary } from './binary';
2
2
  import type { Document } from './bson';
3
3
  import { Code } from './code';
4
- import { DBRef } from './db_ref';
4
+ import { DBRef, isDBRefLike } from './db_ref';
5
5
  import { Decimal128 } from './decimal128';
6
6
  import { Double } from './double';
7
7
  import { Int32 } from './int_32';
@@ -9,7 +9,7 @@ import { Long } from './long';
9
9
  import { MaxKey } from './max_key';
10
10
  import { MinKey } from './min_key';
11
11
  import { ObjectId } from './objectid';
12
- import { isObjectLike } from './parser/utils';
12
+ import { isDate, isObjectLike, isRegExp } from './parser/utils';
13
13
  import { BSONRegExp } from './regexp';
14
14
  import { BSONSymbol } from './symbol';
15
15
  import { Timestamp } from './timestamp';
@@ -120,7 +120,7 @@ function deserializeValue(value: any, options: EJSON.Options = {}) {
120
120
  return Code.fromExtendedJSON(value);
121
121
  }
122
122
 
123
- if (value.$ref != null || value.$dbPointer != null) {
123
+ if (isDBRefLike(value) || value.$dbPointer) {
124
124
  const v = value.$ref ? value : value.$dbPointer;
125
125
 
126
126
  // we run into this in a "degenerate EJSON" case (with $id and $ref order flipped)
@@ -140,9 +140,20 @@ function deserializeValue(value: any, options: EJSON.Options = {}) {
140
140
  return value;
141
141
  }
142
142
 
143
+ type EJSONSerializeOptions = EJSON.Options & {
144
+ seenObjects: { obj: unknown; propertyName: string }[];
145
+ };
146
+
143
147
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
144
- function serializeArray(array: any[], options: EJSON.Options): any[] {
145
- return array.map((v: unknown) => serializeValue(v, options));
148
+ function serializeArray(array: any[], options: EJSONSerializeOptions): any[] {
149
+ return array.map((v: unknown, index: number) => {
150
+ options.seenObjects.push({ propertyName: `index ${index}`, obj: null });
151
+ try {
152
+ return serializeValue(v, options);
153
+ } finally {
154
+ options.seenObjects.pop();
155
+ }
156
+ });
146
157
  }
147
158
 
148
159
  function getISOString(date: Date) {
@@ -152,12 +163,42 @@ function getISOString(date: Date) {
152
163
  }
153
164
 
154
165
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
155
- function serializeValue(value: any, options: EJSON.Options): any {
166
+ function serializeValue(value: any, options: EJSONSerializeOptions): any {
167
+ if ((typeof value === 'object' || typeof value === 'function') && value !== null) {
168
+ const index = options.seenObjects.findIndex(entry => entry.obj === value);
169
+ if (index !== -1) {
170
+ const props = options.seenObjects.map(entry => entry.propertyName);
171
+ const leadingPart = props
172
+ .slice(0, index)
173
+ .map(prop => `${prop} -> `)
174
+ .join('');
175
+ const alreadySeen = props[index];
176
+ const circularPart =
177
+ ' -> ' +
178
+ props
179
+ .slice(index + 1, props.length - 1)
180
+ .map(prop => `${prop} -> `)
181
+ .join('');
182
+ const current = props[props.length - 1];
183
+ const leadingSpace = ' '.repeat(leadingPart.length + alreadySeen.length / 2);
184
+ const dashes = '-'.repeat(
185
+ circularPart.length + (alreadySeen.length + current.length) / 2 - 1
186
+ );
187
+
188
+ throw new TypeError(
189
+ 'Converting circular structure to EJSON:\n' +
190
+ ` ${leadingPart}${alreadySeen}${circularPart}${current}\n` +
191
+ ` ${leadingSpace}\\${dashes}/`
192
+ );
193
+ }
194
+ options.seenObjects[options.seenObjects.length - 1].obj = value;
195
+ }
196
+
156
197
  if (Array.isArray(value)) return serializeArray(value, options);
157
198
 
158
199
  if (value === undefined) return null;
159
200
 
160
- if (value instanceof Date) {
201
+ if (value instanceof Date || isDate(value)) {
161
202
  const dateNum = value.getTime(),
162
203
  // is it in year range 1970-9999?
163
204
  inRange = dateNum > -1 && dateNum < 253402318800000;
@@ -172,7 +213,7 @@ function serializeValue(value: any, options: EJSON.Options): any {
172
213
  : { $date: { $numberLong: value.getTime().toString() } };
173
214
  }
174
215
 
175
- if (typeof value === 'number' && !options.relaxed) {
216
+ if (typeof value === 'number' && (!options.relaxed || !isFinite(value))) {
176
217
  // it's an integer
177
218
  if (Math.floor(value) === value) {
178
219
  const int32Range = value >= BSON_INT32_MIN && value <= BSON_INT32_MAX,
@@ -185,7 +226,7 @@ function serializeValue(value: any, options: EJSON.Options): any {
185
226
  return { $numberDouble: value.toString() };
186
227
  }
187
228
 
188
- if (value instanceof RegExp) {
229
+ if (value instanceof RegExp || isRegExp(value)) {
189
230
  let flags = value.flags;
190
231
  if (flags === undefined) {
191
232
  const match = value.toString().match(/[gimuy]*$/);
@@ -232,7 +273,7 @@ const BSON_TYPE_MAPPINGS = {
232
273
  } as const;
233
274
 
234
275
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
235
- function serializeDocument(doc: any, options: EJSON.Options) {
276
+ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
236
277
  if (doc == null || typeof doc !== 'object') throw new Error('not an object instance');
237
278
 
238
279
  const bsontype: BSONType['_bsontype'] = doc._bsontype;
@@ -240,7 +281,12 @@ function serializeDocument(doc: any, options: EJSON.Options) {
240
281
  // It's a regular object. Recursively serialize its property values.
241
282
  const _doc: Document = {};
242
283
  for (const name in doc) {
243
- _doc[name] = serializeValue(doc[name], options);
284
+ options.seenObjects.push({ propertyName: name, obj: null });
285
+ try {
286
+ _doc[name] = serializeValue(doc[name], options);
287
+ } finally {
288
+ options.seenObjects.pop();
289
+ }
244
290
  }
245
291
  return _doc;
246
292
  } else if (isBSONType(doc)) {
@@ -264,10 +310,10 @@ function serializeDocument(doc: any, options: EJSON.Options) {
264
310
  outDoc = new Code(outDoc.code, serializeValue(outDoc.scope, options));
265
311
  } else if (bsontype === 'DBRef' && outDoc.oid) {
266
312
  outDoc = new DBRef(
267
- outDoc.collection,
313
+ serializeValue(outDoc.collection, options),
268
314
  serializeValue(outDoc.oid, options),
269
- outDoc.db,
270
- outDoc.fields
315
+ serializeValue(outDoc.db, options),
316
+ serializeValue(outDoc.fields, options)
271
317
  );
272
318
  }
273
319
 
@@ -365,9 +411,11 @@ export namespace EJSON {
365
411
  replacer = undefined;
366
412
  space = 0;
367
413
  }
368
- options = Object.assign({}, { relaxed: true, legacy: false }, options);
414
+ const serializeOptions = Object.assign({ relaxed: true, legacy: false }, options, {
415
+ seenObjects: [{ propertyName: '(root)', obj: null }]
416
+ });
369
417
 
370
- const doc = serializeValue(value, options);
418
+ const doc = serializeValue(value, serializeOptions);
371
419
  return JSON.stringify(doc, replacer as Parameters<JSON['stringify']>[1], space);
372
420
  }
373
421
 
package/src/int_32.ts CHANGED
@@ -12,13 +12,15 @@ export interface Int32Extended {
12
12
  export class Int32 {
13
13
  _bsontype!: 'Int32';
14
14
 
15
- value: number;
15
+ value!: number;
16
16
  /**
17
17
  * Create an Int32 type
18
18
  *
19
19
  * @param value - the number we want to represent as an int32.
20
20
  */
21
21
  constructor(value: number | string) {
22
+ if (!(this instanceof Int32)) return new Int32(value);
23
+
22
24
  if ((value as unknown) instanceof Number) {
23
25
  value = value.valueOf();
24
26
  }
@@ -57,7 +59,7 @@ export class Int32 {
57
59
  }
58
60
 
59
61
  inspect(): string {
60
- return `Int32(${this.valueOf()})`;
62
+ return `new Int32(${this.valueOf()})`;
61
63
  }
62
64
  }
63
65
 
package/src/long.ts CHANGED
@@ -82,29 +82,43 @@ export class Long {
82
82
  /**
83
83
  * The high 32 bits as a signed value.
84
84
  */
85
- high: number;
85
+ high!: number;
86
86
 
87
87
  /**
88
88
  * The low 32 bits as a signed value.
89
89
  */
90
- low: number;
90
+ low!: number;
91
91
 
92
92
  /**
93
93
  * Whether unsigned or not.
94
94
  */
95
- unsigned: boolean;
95
+ unsigned!: boolean;
96
96
 
97
97
  /**
98
98
  * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers.
99
99
  * See the from* functions below for more convenient ways of constructing Longs.
100
+ *
101
+ * Acceptable signatures are:
102
+ * - Long(low, high, unsigned?)
103
+ * - Long(bigint, unsigned?)
104
+ * - Long(string, unsigned?)
105
+ *
100
106
  * @param low - The low (signed) 32 bits of the long
101
107
  * @param high - The high (signed) 32 bits of the long
102
108
  * @param unsigned - Whether unsigned or not, defaults to signed
103
109
  */
104
- constructor(low = 0, high = 0, unsigned?: boolean) {
105
- this.low = low | 0;
106
- this.high = high | 0;
107
- this.unsigned = !!unsigned;
110
+ constructor(low: number | bigint | string = 0, high?: number | boolean, unsigned?: boolean) {
111
+ if (!(this instanceof Long)) return new Long(low, high, unsigned);
112
+
113
+ if (typeof low === 'bigint') {
114
+ Object.assign(this, Long.fromBigInt(low, !!high));
115
+ } else if (typeof low === 'string') {
116
+ Object.assign(this, Long.fromString(low, !!high));
117
+ } else {
118
+ this.low = low | 0;
119
+ this.high = (high as number) | 0;
120
+ this.unsigned = !!unsigned;
121
+ }
108
122
 
109
123
  Object.defineProperty(this, '__isLong__', {
110
124
  value: true,
@@ -992,7 +1006,7 @@ export class Long {
992
1006
  }
993
1007
 
994
1008
  inspect(): string {
995
- return `Long("${this.toString()}")`;
1009
+ return `new Long("${this.toString()}"${this.unsigned ? ', true' : ''})`;
996
1010
  }
997
1011
  }
998
1012
 
package/src/max_key.ts CHANGED
@@ -10,6 +10,10 @@ export interface MaxKeyExtended {
10
10
  export class MaxKey {
11
11
  _bsontype!: 'MaxKey';
12
12
 
13
+ constructor() {
14
+ if (!(this instanceof MaxKey)) return new MaxKey();
15
+ }
16
+
13
17
  /** @internal */
14
18
  toExtendedJSON(): MaxKeyExtended {
15
19
  return { $maxKey: 1 };
@@ -26,7 +30,7 @@ export class MaxKey {
26
30
  }
27
31
 
28
32
  inspect(): string {
29
- return 'MaxKey()';
33
+ return 'new MaxKey()';
30
34
  }
31
35
  }
32
36
 
package/src/min_key.ts CHANGED
@@ -10,6 +10,10 @@ export interface MinKeyExtended {
10
10
  export class MinKey {
11
11
  _bsontype!: 'MinKey';
12
12
 
13
+ constructor() {
14
+ if (!(this instanceof MinKey)) return new MinKey();
15
+ }
16
+
13
17
  /** @internal */
14
18
  toExtendedJSON(): MinKeyExtended {
15
19
  return { $minKey: 1 };
@@ -26,7 +30,7 @@ export class MinKey {
26
30
  }
27
31
 
28
32
  inspect(): string {
29
- return 'MinKey()';
33
+ return 'new MinKey()';
30
34
  }
31
35
  }
32
36
 
package/src/objectid.ts CHANGED
@@ -1,24 +1,12 @@
1
1
  import { Buffer } from 'buffer';
2
2
  import { ensureBuffer } from './ensure_buffer';
3
- import { deprecate, randomBytes } from './parser/utils';
4
-
5
- // constants
6
- const PROCESS_UNIQUE = randomBytes(5);
3
+ import { deprecate, isUint8Array, randomBytes } from './parser/utils';
7
4
 
8
5
  // Regular expression that checks for hex value
9
6
  const checkForHexRegExp = new RegExp('^[0-9a-fA-F]{24}$');
10
7
 
11
- // Precomputed hex table enables speedy hex string conversion
12
- const hexTable: string[] = [];
13
- for (let i = 0; i < 256; i++) {
14
- hexTable[i] = (i <= 15 ? '0' : '') + i.toString(16);
15
- }
16
-
17
- // Lookup tables
18
- const decodeLookup: number[] = [];
19
- let i = 0;
20
- while (i < 10) decodeLookup[0x30 + i] = i++;
21
- while (i < 16) decodeLookup[0x41 - 10 + i] = decodeLookup[0x61 - 10 + i] = i++;
8
+ // Unique sequence for the current process (initialized on first use)
9
+ let PROCESS_UNIQUE: Uint8Array | null = null;
22
10
 
23
11
  /** @public */
24
12
  export interface ObjectIdLike {
@@ -57,6 +45,8 @@ export class ObjectId {
57
45
  * @param id - Can be a 24 character hex string, 12 byte binary Buffer, or a number.
58
46
  */
59
47
  constructor(id?: string | Buffer | number | ObjectIdLike | ObjectId) {
48
+ if (!(this instanceof ObjectId)) return new ObjectId(id);
49
+
60
50
  // Duck-typing to support ObjectId from different npm packages
61
51
  if (id instanceof ObjectId) {
62
52
  this[kId] = id.id;
@@ -174,6 +164,11 @@ export class ObjectId {
174
164
  // 4-byte timestamp
175
165
  buffer.writeUInt32BE(time, 0);
176
166
 
167
+ // set PROCESS_UNIQUE if yet not initialized
168
+ if (PROCESS_UNIQUE === null) {
169
+ PROCESS_UNIQUE = randomBytes(5);
170
+ }
171
+
177
172
  // 5-byte process unique
178
173
  buffer[4] = PROCESS_UNIQUE[0];
179
174
  buffer[5] = PROCESS_UNIQUE[1];
@@ -227,9 +222,9 @@ export class ObjectId {
227
222
  typeof otherId === 'string' &&
228
223
  ObjectId.isValid(otherId) &&
229
224
  otherId.length === 12 &&
230
- this.id instanceof Buffer
225
+ isUint8Array(this.id)
231
226
  ) {
232
- return otherId === this.id.toString('binary');
227
+ return otherId === Buffer.prototype.toString.call(this.id, 'latin1');
233
228
  }
234
229
 
235
230
  if (typeof otherId === 'string' && ObjectId.isValid(otherId) && otherId.length === 24) {
@@ -298,7 +293,7 @@ export class ObjectId {
298
293
  *
299
294
  * @param id - ObjectId instance to validate.
300
295
  */
301
- static isValid(id: number | string | ObjectId | Buffer | ObjectIdLike): boolean {
296
+ static isValid(id: number | string | ObjectId | Uint8Array | ObjectIdLike): boolean {
302
297
  if (id == null) return false;
303
298
 
304
299
  if (typeof id === 'number') {
@@ -313,7 +308,7 @@ export class ObjectId {
313
308
  return true;
314
309
  }
315
310
 
316
- if (id instanceof Buffer && id.length === 12) {
311
+ if (isUint8Array(id) && id.length === 12) {
317
312
  return true;
318
313
  }
319
314
 
@@ -350,7 +345,7 @@ export class ObjectId {
350
345
  }
351
346
 
352
347
  inspect(): string {
353
- return `ObjectId("${this.toHexString()}")`;
348
+ return `new ObjectId("${this.toHexString()}")`;
354
349
  }
355
350
  }
356
351
 
@@ -2,7 +2,7 @@ import { Buffer } from 'buffer';
2
2
  import { Binary } from '../binary';
3
3
  import type { Document } from '../bson';
4
4
  import * as constants from '../constants';
5
- import { isDate, normalizedFunctionString } from './utils';
5
+ import { isAnyArrayBuffer, isDate, isRegExp, normalizedFunctionString } from './utils';
6
6
 
7
7
  export function calculateObjectSize(
8
8
  object: Document,
@@ -83,7 +83,11 @@ function calculateElement(
83
83
  return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (12 + 1);
84
84
  } else if (value instanceof Date || isDate(value)) {
85
85
  return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (8 + 1);
86
- } else if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
86
+ } else if (
87
+ ArrayBuffer.isView(value) ||
88
+ value instanceof ArrayBuffer ||
89
+ isAnyArrayBuffer(value)
90
+ ) {
87
91
  return (
88
92
  (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (1 + 4 + 1) + value.byteLength
89
93
  );
@@ -156,10 +160,7 @@ function calculateElement(
156
160
  1 +
157
161
  calculateObjectSize(ordered_values, serializeFunctions, ignoreUndefined)
158
162
  );
159
- } else if (
160
- value instanceof RegExp ||
161
- Object.prototype.toString.call(value) === '[object RegExp]'
162
- ) {
163
+ } else if (value instanceof RegExp || isRegExp(value)) {
163
164
  return (
164
165
  (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) +
165
166
  1 +
@@ -188,11 +189,7 @@ function calculateElement(
188
189
  }
189
190
  case 'function':
190
191
  // WTF for 0.4.X where typeof /someregexp/ === 'function'
191
- if (
192
- value instanceof RegExp ||
193
- Object.prototype.toString.call(value) === '[object RegExp]' ||
194
- String.call(value) === '[object RegExp]'
195
- ) {
192
+ if (value instanceof RegExp || isRegExp(value) || String.call(value) === '[object RegExp]') {
196
193
  return (
197
194
  (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) +
198
195
  1 +
@@ -152,6 +152,7 @@ function deserializeObject(
152
152
  // If are at the end of the buffer there is a problem with the document
153
153
  if (i >= buffer.byteLength) throw new Error('Bad BSON Document: illegal CString');
154
154
  const name = isArray ? arrayIndex++ : buffer.toString('utf8', index, i);
155
+ let value;
155
156
 
156
157
  index = i + 1;
157
158
 
@@ -172,30 +173,29 @@ function deserializeObject(
172
173
  throw new Error('Invalid UTF-8 string in BSON document');
173
174
  }
174
175
 
175
- const s = buffer.toString('utf8', index, index + stringSize - 1);
176
+ value = buffer.toString('utf8', index, index + stringSize - 1);
176
177
 
177
- object[name] = s;
178
178
  index = index + stringSize;
179
179
  } else if (elementType === constants.BSON_DATA_OID) {
180
180
  const oid = Buffer.alloc(12);
181
181
  buffer.copy(oid, 0, index, index + 12);
182
- object[name] = new ObjectId(oid);
182
+ value = new ObjectId(oid);
183
183
  index = index + 12;
184
184
  } else if (elementType === constants.BSON_DATA_INT && promoteValues === false) {
185
- object[name] = new Int32(
185
+ value = new Int32(
186
186
  buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24)
187
187
  );
188
188
  } else if (elementType === constants.BSON_DATA_INT) {
189
- object[name] =
189
+ value =
190
190
  buffer[index++] |
191
191
  (buffer[index++] << 8) |
192
192
  (buffer[index++] << 16) |
193
193
  (buffer[index++] << 24);
194
194
  } else if (elementType === constants.BSON_DATA_NUMBER && promoteValues === false) {
195
- object[name] = new Double(buffer.readDoubleLE(index));
195
+ value = new Double(buffer.readDoubleLE(index));
196
196
  index = index + 8;
197
197
  } else if (elementType === constants.BSON_DATA_NUMBER) {
198
- object[name] = buffer.readDoubleLE(index);
198
+ value = buffer.readDoubleLE(index);
199
199
  index = index + 8;
200
200
  } else if (elementType === constants.BSON_DATA_DATE) {
201
201
  const lowBits =
@@ -208,10 +208,10 @@ function deserializeObject(
208
208
  (buffer[index++] << 8) |
209
209
  (buffer[index++] << 16) |
210
210
  (buffer[index++] << 24);
211
- object[name] = new Date(new Long(lowBits, highBits).toNumber());
211
+ value = new Date(new Long(lowBits, highBits).toNumber());
212
212
  } else if (elementType === constants.BSON_DATA_BOOLEAN) {
213
213
  if (buffer[index] !== 0 && buffer[index] !== 1) throw new Error('illegal boolean type value');
214
- object[name] = buffer[index++] === 1;
214
+ value = buffer[index++] === 1;
215
215
  } else if (elementType === constants.BSON_DATA_OBJECT) {
216
216
  const _index = index;
217
217
  const objectSize =
@@ -224,9 +224,9 @@ function deserializeObject(
224
224
 
225
225
  // We have a raw value
226
226
  if (raw) {
227
- object[name] = buffer.slice(index, index + objectSize);
227
+ value = buffer.slice(index, index + objectSize);
228
228
  } else {
229
- object[name] = deserializeObject(buffer, _index, options, false);
229
+ value = deserializeObject(buffer, _index, options, false);
230
230
  }
231
231
 
232
232
  index = index + objectSize;
@@ -253,15 +253,15 @@ function deserializeObject(
253
253
  arrayOptions['raw'] = true;
254
254
  }
255
255
 
256
- object[name] = deserializeObject(buffer, _index, arrayOptions, true);
256
+ value = deserializeObject(buffer, _index, arrayOptions, true);
257
257
  index = index + objectSize;
258
258
 
259
259
  if (buffer[index - 1] !== 0) throw new Error('invalid array terminator byte');
260
260
  if (index !== stopIndex) throw new Error('corrupted array bson');
261
261
  } else if (elementType === constants.BSON_DATA_UNDEFINED) {
262
- object[name] = undefined;
262
+ value = undefined;
263
263
  } else if (elementType === constants.BSON_DATA_NULL) {
264
- object[name] = null;
264
+ value = null;
265
265
  } else if (elementType === constants.BSON_DATA_LONG) {
266
266
  // Unpack the low and high bits
267
267
  const lowBits =
@@ -277,12 +277,12 @@ function deserializeObject(
277
277
  const long = new Long(lowBits, highBits);
278
278
  // Promote the long if possible
279
279
  if (promoteLongs && promoteValues === true) {
280
- object[name] =
280
+ value =
281
281
  long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
282
282
  ? long.toNumber()
283
283
  : long;
284
284
  } else {
285
- object[name] = long;
285
+ value = long;
286
286
  }
287
287
  } else if (elementType === constants.BSON_DATA_DECIMAL128) {
288
288
  // Buffer to contain the decimal bytes
@@ -295,9 +295,9 @@ function deserializeObject(
295
295
  const decimal128 = new Decimal128(bytes) as Decimal128 | { toObject(): unknown };
296
296
  // If we have an alternative mapper use that
297
297
  if ('toObject' in decimal128 && typeof decimal128.toObject === 'function') {
298
- object[name] = decimal128.toObject();
298
+ value = decimal128.toObject();
299
299
  } else {
300
- object[name] = decimal128;
300
+ value = decimal128;
301
301
  }
302
302
  } else if (elementType === constants.BSON_DATA_BINARY) {
303
303
  let binarySize =
@@ -333,9 +333,9 @@ function deserializeObject(
333
333
  }
334
334
 
335
335
  if (promoteBuffers && promoteValues) {
336
- object[name] = buffer.slice(index, index + binarySize);
336
+ value = buffer.slice(index, index + binarySize);
337
337
  } else {
338
- object[name] = new Binary(buffer.slice(index, index + binarySize), subType);
338
+ value = new Binary(buffer.slice(index, index + binarySize), subType);
339
339
  }
340
340
  } else {
341
341
  const _buffer = Buffer.alloc(binarySize);
@@ -360,9 +360,9 @@ function deserializeObject(
360
360
  }
361
361
 
362
362
  if (promoteBuffers && promoteValues) {
363
- object[name] = _buffer;
363
+ value = _buffer;
364
364
  } else {
365
- object[name] = new Binary(_buffer, subType);
365
+ value = new Binary(_buffer, subType);
366
366
  }
367
367
  }
368
368
 
@@ -412,7 +412,7 @@ function deserializeObject(
412
412
  }
413
413
  }
414
414
 
415
- object[name] = new RegExp(source, optionsArray.join(''));
415
+ value = new RegExp(source, optionsArray.join(''));
416
416
  } else if (elementType === constants.BSON_DATA_REGEXP && bsonRegExp === true) {
417
417
  // Get the start search index
418
418
  i = index;
@@ -439,7 +439,7 @@ function deserializeObject(
439
439
  index = i + 1;
440
440
 
441
441
  // Set the object
442
- object[name] = new BSONRegExp(source, regExpOptions);
442
+ value = new BSONRegExp(source, regExpOptions);
443
443
  } else if (elementType === constants.BSON_DATA_SYMBOL) {
444
444
  const stringSize =
445
445
  buffer[index++] |
@@ -453,7 +453,7 @@ function deserializeObject(
453
453
  )
454
454
  throw new Error('bad string length in bson');
455
455
  const symbol = buffer.toString('utf8', index, index + stringSize - 1);
456
- object[name] = promoteValues ? symbol : new BSONSymbol(symbol);
456
+ value = promoteValues ? symbol : new BSONSymbol(symbol);
457
457
  index = index + stringSize;
458
458
  } else if (elementType === constants.BSON_DATA_TIMESTAMP) {
459
459
  const lowBits =
@@ -467,11 +467,11 @@ function deserializeObject(
467
467
  (buffer[index++] << 16) |
468
468
  (buffer[index++] << 24);
469
469
 
470
- object[name] = new Timestamp(lowBits, highBits);
470
+ value = new Timestamp(lowBits, highBits);
471
471
  } else if (elementType === constants.BSON_DATA_MIN_KEY) {
472
- object[name] = new MinKey();
472
+ value = new MinKey();
473
473
  } else if (elementType === constants.BSON_DATA_MAX_KEY) {
474
- object[name] = new MaxKey();
474
+ value = new MaxKey();
475
475
  } else if (elementType === constants.BSON_DATA_CODE) {
476
476
  const stringSize =
477
477
  buffer[index++] |
@@ -491,12 +491,12 @@ function deserializeObject(
491
491
  // If we have cache enabled let's look for the md5 of the function in the cache
492
492
  if (cacheFunctions) {
493
493
  // Got to do this to avoid V8 deoptimizing the call due to finding eval
494
- object[name] = isolateEval(functionString, functionCache, object);
494
+ value = isolateEval(functionString, functionCache, object);
495
495
  } else {
496
- object[name] = isolateEval(functionString);
496
+ value = isolateEval(functionString);
497
497
  }
498
498
  } else {
499
- object[name] = new Code(functionString);
499
+ value = new Code(functionString);
500
500
  }
501
501
 
502
502
  // Update parse index position
@@ -559,14 +559,14 @@ function deserializeObject(
559
559
  // If we have cache enabled let's look for the md5 of the function in the cache
560
560
  if (cacheFunctions) {
561
561
  // Got to do this to avoid V8 deoptimizing the call due to finding eval
562
- object[name] = isolateEval(functionString, functionCache, object);
562
+ value = isolateEval(functionString, functionCache, object);
563
563
  } else {
564
- object[name] = isolateEval(functionString);
564
+ value = isolateEval(functionString);
565
565
  }
566
566
 
567
- object[name].scope = scopeObject;
567
+ value.scope = scopeObject;
568
568
  } else {
569
- object[name] = new Code(functionString, scopeObject);
569
+ value = new Code(functionString, scopeObject);
570
570
  }
571
571
  } else if (elementType === constants.BSON_DATA_DBPOINTER) {
572
572
  // Get the code string size
@@ -599,12 +599,22 @@ function deserializeObject(
599
599
  index = index + 12;
600
600
 
601
601
  // Upgrade to DBRef type
602
- object[name] = new DBRef(namespace, oid);
602
+ value = new DBRef(namespace, oid);
603
603
  } else {
604
604
  throw new Error(
605
605
  'Detected unknown BSON type ' + elementType.toString(16) + ' for fieldname "' + name + '"'
606
606
  );
607
607
  }
608
+ if (name === '__proto__') {
609
+ Object.defineProperty(object, name, {
610
+ value,
611
+ writable: true,
612
+ enumerable: true,
613
+ configurable: true
614
+ });
615
+ } else {
616
+ object[name] = value;
617
+ }
608
618
  }
609
619
 
610
620
  // Check if the deserialization was against a valid array/object