bson 5.0.0-alpha.0 → 5.0.0-alpha.2

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/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "etc/prepare.js"
14
14
  ],
15
15
  "types": "bson.d.ts",
16
- "version": "5.0.0-alpha.0",
16
+ "version": "5.0.0-alpha.2",
17
17
  "author": {
18
18
  "name": "The MongoDB NodeJS Team",
19
19
  "email": "dbx-node@mongodb.com"
@@ -75,11 +75,11 @@
75
75
  },
76
76
  "main": "./lib/bson.cjs",
77
77
  "module": "./lib/bson.mjs",
78
- "browser": "./lib/bson.mjs",
79
78
  "exports": {
80
- "browser": "./lib/bson.mjs",
81
79
  "import": "./lib/bson.mjs",
82
- "require": "./lib/bson.cjs"
80
+ "require": "./lib/bson.cjs",
81
+ "react-native": "./lib/bson.cjs",
82
+ "browser": "./lib/bson.mjs"
83
83
  },
84
84
  "engines": {
85
85
  "node": ">=14.20.1"
package/src/binary.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { bufferToUuidHexString, uuidHexStringToBuffer, uuidValidateString } from './uuid_utils';
2
2
  import { isUint8Array } from './parser/utils';
3
3
  import type { EJSONOptions } from './extended_json';
4
- import { BSONError, BSONTypeError } from './error';
5
- import { BSON_BINARY_SUBTYPE_UUID_NEW } from './constants';
4
+ import { BSONError } from './error';
5
+ import { BSON_BINARY_SUBTYPE_UUID_NEW, BSON_MAJOR_VERSION } from './constants';
6
6
  import { ByteUtils } from './utils/byte_utils';
7
7
 
8
8
  /** @public */
@@ -32,8 +32,8 @@ export class Binary {
32
32
  return 'Binary';
33
33
  }
34
34
  /** @internal */
35
- get [Symbol.for('@@mdb.bson.version')](): 5 {
36
- return 5;
35
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
36
+ return BSON_MAJOR_VERSION;
37
37
  }
38
38
 
39
39
  /**
@@ -86,7 +86,7 @@ export class Binary {
86
86
  !(buffer instanceof ArrayBuffer) &&
87
87
  !Array.isArray(buffer)
88
88
  ) {
89
- throw new BSONTypeError(
89
+ throw new BSONError(
90
90
  'Binary can only be constructed from string, Buffer, TypedArray, or Array<number>'
91
91
  );
92
92
  }
@@ -121,9 +121,9 @@ export class Binary {
121
121
  put(byteValue: string | number | Uint8Array | number[]): void {
122
122
  // If it's a string and a has more than one character throw an error
123
123
  if (typeof byteValue === 'string' && byteValue.length !== 1) {
124
- throw new BSONTypeError('only accepts single character String');
124
+ throw new BSONError('only accepts single character String');
125
125
  } else if (typeof byteValue !== 'number' && byteValue.length !== 1)
126
- throw new BSONTypeError('only accepts single character Uint8Array or Array');
126
+ throw new BSONError('only accepts single character Uint8Array or Array');
127
127
 
128
128
  // Decode the byte value once
129
129
  let decodedByte: number;
@@ -136,7 +136,7 @@ export class Binary {
136
136
  }
137
137
 
138
138
  if (decodedByte < 0 || decodedByte > 255) {
139
- throw new BSONTypeError('only accepts number in a valid unsigned byte range 0-255');
139
+ throw new BSONError('only accepts number in a valid unsigned byte range 0-255');
140
140
  }
141
141
 
142
142
  if (this.buffer.byteLength > this.position) {
@@ -283,7 +283,7 @@ export class Binary {
283
283
  data = uuidHexStringToBuffer(doc.$uuid);
284
284
  }
285
285
  if (!data) {
286
- throw new BSONTypeError(`Unexpected Binary Extended JSON format ${JSON.stringify(doc)}`);
286
+ throw new BSONError(`Unexpected Binary Extended JSON format ${JSON.stringify(doc)}`);
287
287
  }
288
288
  return type === BSON_BINARY_SUBTYPE_UUID_NEW ? new UUID(data) : new Binary(data, type);
289
289
  }
@@ -310,8 +310,8 @@ const UUID_BYTE_LENGTH = 16;
310
310
  */
311
311
  export class UUID extends Binary {
312
312
  /** @internal */
313
- get [Symbol.for('@@mdb.bson.version')](): 5 {
314
- return 5;
313
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
314
+ return BSON_MAJOR_VERSION;
315
315
  }
316
316
 
317
317
  static cacheHexString: boolean;
@@ -337,7 +337,7 @@ export class UUID extends Binary {
337
337
  } else if (typeof input === 'string') {
338
338
  bytes = uuidHexStringToBuffer(input);
339
339
  } else {
340
- throw new BSONTypeError(
340
+ throw new BSONError(
341
341
  'Argument passed in UUID constructor must be a UUID, a 16 byte Buffer or a 32/36 character hex string (dashes excluded/included, format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).'
342
342
  );
343
343
  }
package/src/bson.ts CHANGED
@@ -49,7 +49,7 @@ export {
49
49
  BSONRegExp,
50
50
  Decimal128
51
51
  };
52
- export { BSONError, BSONTypeError } from './error';
52
+ export { BSONError } from './error';
53
53
  export { BSONType } from './constants';
54
54
  export { EJSON } from './extended_json';
55
55
 
package/src/code.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Document } from './bson';
2
+ import { BSON_MAJOR_VERSION } from './constants';
2
3
 
3
4
  /** @public */
4
5
  export interface CodeExtended {
@@ -16,8 +17,8 @@ export class Code {
16
17
  return 'Code';
17
18
  }
18
19
  /** @internal */
19
- get [Symbol.for('@@mdb.bson.version')](): 5 {
20
- return 5;
20
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
21
+ return BSON_MAJOR_VERSION;
21
22
  }
22
23
 
23
24
  code: string;
package/src/constants.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /** @internal */
2
+ export type BSON_MAJOR_VERSION = 5;
3
+ /** @internal */
4
+ export const BSON_MAJOR_VERSION: BSON_MAJOR_VERSION = 5;
5
+
1
6
  /** @internal */
2
7
  export const BSON_INT32_MAX = 0x7fffffff;
3
8
  /** @internal */
package/src/db_ref.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Document } from './bson';
2
+ import { BSON_MAJOR_VERSION } from './constants';
2
3
  import type { EJSONOptions } from './extended_json';
3
4
  import type { ObjectId } from './objectid';
4
5
 
@@ -33,8 +34,8 @@ export class DBRef {
33
34
  return 'DBRef';
34
35
  }
35
36
  /** @internal */
36
- get [Symbol.for('@@mdb.bson.version')](): 5 {
37
- return 5;
37
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
38
+ return BSON_MAJOR_VERSION;
38
39
  }
39
40
 
40
41
  collection!: string;
package/src/decimal128.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { BSONTypeError } from './error';
1
+ import { BSON_MAJOR_VERSION } from './constants';
2
+ import { BSONError } from './error';
2
3
  import { Long } from './long';
3
4
  import { isUint8Array } from './parser/utils';
4
5
  import { ByteUtils } from './utils/byte_utils';
@@ -113,7 +114,7 @@ function lessThan(left: Long, right: Long): boolean {
113
114
  }
114
115
 
115
116
  function invalidErr(string: string, message: string) {
116
- throw new BSONTypeError(`"${string}" is not a valid Decimal128 string - ${message}`);
117
+ throw new BSONError(`"${string}" is not a valid Decimal128 string - ${message}`);
117
118
  }
118
119
 
119
120
  /** @public */
@@ -131,8 +132,8 @@ export class Decimal128 {
131
132
  return 'Decimal128';
132
133
  }
133
134
  /** @internal */
134
- get [Symbol.for('@@mdb.bson.version')](): 5 {
135
- return 5;
135
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
136
+ return BSON_MAJOR_VERSION;
136
137
  }
137
138
 
138
139
  readonly bytes!: Uint8Array;
@@ -146,11 +147,11 @@ export class Decimal128 {
146
147
  this.bytes = Decimal128.fromString(bytes).bytes;
147
148
  } else if (isUint8Array(bytes)) {
148
149
  if (bytes.byteLength !== 16) {
149
- throw new BSONTypeError('Decimal128 must take a Buffer of 16 bytes');
150
+ throw new BSONError('Decimal128 must take a Buffer of 16 bytes');
150
151
  }
151
152
  this.bytes = bytes;
152
153
  } else {
153
- throw new BSONTypeError('Decimal128 must take a Buffer or string');
154
+ throw new BSONError('Decimal128 must take a Buffer or string');
154
155
  }
155
156
  }
156
157
 
@@ -205,7 +206,7 @@ export class Decimal128 {
205
206
  // TODO: implementing a custom parsing for this, or refactoring the regex would yield
206
207
  // further gains.
207
208
  if (representation.length >= 7000) {
208
- throw new BSONTypeError('' + representation + ' not a valid Decimal128 string');
209
+ throw new BSONError('' + representation + ' not a valid Decimal128 string');
209
210
  }
210
211
 
211
212
  // Results
@@ -215,7 +216,7 @@ export class Decimal128 {
215
216
 
216
217
  // Validate the string
217
218
  if ((!stringMatch && !infMatch && !nanMatch) || representation.length === 0) {
218
- throw new BSONTypeError('' + representation + ' not a valid Decimal128 string');
219
+ throw new BSONError('' + representation + ' not a valid Decimal128 string');
219
220
  }
220
221
 
221
222
  if (stringMatch) {
@@ -287,7 +288,7 @@ export class Decimal128 {
287
288
  }
288
289
 
289
290
  if (sawRadix && !nDigitsRead)
290
- throw new BSONTypeError('' + representation + ' not a valid Decimal128 string');
291
+ throw new BSONError('' + representation + ' not a valid Decimal128 string');
291
292
 
292
293
  // Read exponent if exists
293
294
  if (representation[index] === 'e' || representation[index] === 'E') {
package/src/double.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { BSON_MAJOR_VERSION } from './constants';
1
2
  import type { EJSONOptions } from './extended_json';
2
3
 
3
4
  /** @public */
@@ -15,8 +16,8 @@ export class Double {
15
16
  return 'Double';
16
17
  }
17
18
  /** @internal */
18
- get [Symbol.for('@@mdb.bson.version')](): 5 {
19
- return 5;
19
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
20
+ return BSON_MAJOR_VERSION;
20
21
  }
21
22
 
22
23
  value!: number;
@@ -56,23 +57,15 @@ export class Double {
56
57
  return this.value;
57
58
  }
58
59
 
59
- // NOTE: JavaScript has +0 and -0, apparently to model limit calculations. If a user
60
- // explicitly provided `-0` then we need to ensure the sign makes it into the output
61
60
  if (Object.is(Math.sign(this.value), -0)) {
62
- return { $numberDouble: `-${this.value.toFixed(1)}` };
61
+ // NOTE: JavaScript has +0 and -0, apparently to model limit calculations. If a user
62
+ // explicitly provided `-0` then we need to ensure the sign makes it into the output
63
+ return { $numberDouble: '-0.0' };
63
64
  }
64
65
 
65
- let $numberDouble: string;
66
- if (Number.isInteger(this.value)) {
67
- $numberDouble = this.value.toFixed(1);
68
- if ($numberDouble.length >= 13) {
69
- $numberDouble = this.value.toExponential(13).toUpperCase();
70
- }
71
- } else {
72
- $numberDouble = this.value.toString();
73
- }
74
-
75
- return { $numberDouble };
66
+ return {
67
+ $numberDouble: Number.isInteger(this.value) ? this.value.toFixed(1) : this.value.toString()
68
+ };
76
69
  }
77
70
 
78
71
  /** @internal */
package/src/error.ts CHANGED
@@ -1,21 +1,45 @@
1
- /** @public */
1
+ /**
2
+ * @public
3
+ * `BSONError` objects are thrown when runtime errors occur.
4
+ */
2
5
  export class BSONError extends Error {
3
- constructor(message: string) {
4
- super(message);
6
+ /**
7
+ * @internal
8
+ * The underlying algorithm for isBSONError may change to improve how strict it is
9
+ * about determining if an input is a BSONError. But it must remain backwards compatible
10
+ * with previous minors & patches of the current major version.
11
+ */
12
+ protected get bsonError(): true {
13
+ return true;
5
14
  }
6
15
 
7
- get name(): string {
16
+ override get name(): string {
8
17
  return 'BSONError';
9
18
  }
10
- }
11
19
 
12
- /** @public */
13
- export class BSONTypeError extends TypeError {
14
20
  constructor(message: string) {
15
21
  super(message);
16
22
  }
17
23
 
18
- get name(): string {
19
- return 'BSONTypeError';
24
+ /**
25
+ * @public
26
+ *
27
+ * All errors thrown from the BSON library inherit from `BSONError`.
28
+ * This method can assist with determining if an error originates from the BSON library
29
+ * even if it does not pass an `instanceof` check against this class' constructor.
30
+ *
31
+ * @param value - any javascript value that needs type checking
32
+ */
33
+ public static isBSONError(value: unknown): value is BSONError {
34
+ return (
35
+ value != null &&
36
+ typeof value === 'object' &&
37
+ 'bsonError' in value &&
38
+ value.bsonError === true &&
39
+ // Do not access the following properties, just check existence
40
+ 'name' in value &&
41
+ 'message' in value &&
42
+ 'stack' in value
43
+ );
20
44
  }
21
45
  }
@@ -1,11 +1,17 @@
1
1
  import { Binary } from './binary';
2
2
  import type { Document } from './bson';
3
3
  import { Code } from './code';
4
- import { BSON_INT32_MAX, BSON_INT32_MIN, BSON_INT64_MAX, BSON_INT64_MIN } from './constants';
4
+ import {
5
+ BSON_INT32_MAX,
6
+ BSON_INT32_MIN,
7
+ BSON_INT64_MAX,
8
+ BSON_INT64_MIN,
9
+ BSON_MAJOR_VERSION
10
+ } from './constants';
5
11
  import { DBRef, isDBRefLike } from './db_ref';
6
12
  import { Decimal128 } from './decimal128';
7
13
  import { Double } from './double';
8
- import { BSONError, BSONTypeError } from './error';
14
+ import { BSONError } from './error';
9
15
  import { Int32 } from './int_32';
10
16
  import { Long } from './long';
11
17
  import { MaxKey } from './max_key';
@@ -192,7 +198,7 @@ function serializeValue(value: any, options: EJSONSerializeOptions): any {
192
198
  circularPart.length + (alreadySeen.length + current.length) / 2 - 1
193
199
  );
194
200
 
195
- throw new BSONTypeError(
201
+ throw new BSONError(
196
202
  'Converting circular structure to EJSON:\n' +
197
203
  ` ${leadingPart}${alreadySeen}${circularPart}${current}\n` +
198
204
  ` ${leadingSpace}\\${dashes}/`
@@ -310,7 +316,7 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
310
316
  doc != null &&
311
317
  typeof doc === 'object' &&
312
318
  typeof doc._bsontype === 'string' &&
313
- doc[Symbol.for('@@mdb.bson.version')] == null
319
+ doc[Symbol.for('@@mdb.bson.version')] !== BSON_MAJOR_VERSION
314
320
  ) {
315
321
  throw new BSONError('Unsupported BSON version, bson types must be from bson 5.0 or later');
316
322
  } else if (isBSONType(doc)) {
@@ -324,7 +330,7 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
324
330
  // Copy the object into this library's version of that type.
325
331
  const mapper = BSON_TYPE_MAPPINGS[doc._bsontype];
326
332
  if (!mapper) {
327
- throw new BSONTypeError('Unrecognized or invalid _bsontype: ' + doc._bsontype);
333
+ throw new BSONError('Unrecognized or invalid _bsontype: ' + doc._bsontype);
328
334
  }
329
335
  outDoc = mapper(outDoc);
330
336
  }
package/src/int_32.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { BSON_MAJOR_VERSION } from './constants';
1
2
  import type { EJSONOptions } from './extended_json';
2
3
 
3
4
  /** @public */
@@ -15,8 +16,8 @@ export class Int32 {
15
16
  return 'Int32';
16
17
  }
17
18
  /** @internal */
18
- get [Symbol.for('@@mdb.bson.version')](): 5 {
19
- return 5;
19
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
20
+ return BSON_MAJOR_VERSION;
20
21
  }
21
22
 
22
23
  value!: number;
package/src/long.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { BSON_MAJOR_VERSION } from './constants';
2
+ import { BSONError } from './error';
1
3
  import type { EJSONOptions } from './extended_json';
2
4
  import type { Timestamp } from './timestamp';
3
5
 
@@ -103,8 +105,8 @@ export class Long {
103
105
  return 'Long';
104
106
  }
105
107
  /** @internal */
106
- get [Symbol.for('@@mdb.bson.version')](): 5 {
107
- return 5;
108
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
109
+ return BSON_MAJOR_VERSION;
108
110
  }
109
111
 
110
112
  /** An indicator used to reliably determine if an object is a Long or not. */
@@ -249,7 +251,7 @@ export class Long {
249
251
  * @returns The corresponding Long value
250
252
  */
251
253
  static fromString(str: string, unsigned?: boolean, radix?: number): Long {
252
- if (str.length === 0) throw Error('empty string');
254
+ if (str.length === 0) throw new BSONError('empty string');
253
255
  if (str === 'NaN' || str === 'Infinity' || str === '+Infinity' || str === '-Infinity')
254
256
  return Long.ZERO;
255
257
  if (typeof unsigned === 'number') {
@@ -259,10 +261,10 @@ export class Long {
259
261
  unsigned = !!unsigned;
260
262
  }
261
263
  radix = radix || 10;
262
- if (radix < 2 || 36 < radix) throw RangeError('radix');
264
+ if (radix < 2 || 36 < radix) throw new BSONError('radix');
263
265
 
264
266
  let p;
265
- if ((p = str.indexOf('-')) > 0) throw Error('interior hyphen');
267
+ if ((p = str.indexOf('-')) > 0) throw new BSONError('interior hyphen');
266
268
  else if (p === 0) {
267
269
  return Long.fromString(str.substring(1), unsigned, radix).neg();
268
270
  }
@@ -430,7 +432,7 @@ export class Long {
430
432
  */
431
433
  divide(divisor: string | number | Long | Timestamp): Long {
432
434
  if (!Long.isLong(divisor)) divisor = Long.fromValue(divisor);
433
- if (divisor.isZero()) throw Error('division by zero');
435
+ if (divisor.isZero()) throw new BSONError('division by zero');
434
436
 
435
437
  // use wasm support if present
436
438
  if (wasm) {
@@ -958,7 +960,7 @@ export class Long {
958
960
  */
959
961
  toString(radix?: number): string {
960
962
  radix = radix || 10;
961
- if (radix < 2 || 36 < radix) throw RangeError('radix');
963
+ if (radix < 2 || 36 < radix) throw new BSONError('radix');
962
964
  if (this.isZero()) return '0';
963
965
  if (this.isNegative()) {
964
966
  // Unsigned Longs are never negative
package/src/max_key.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { BSON_MAJOR_VERSION } from './constants';
2
+
1
3
  /** @public */
2
4
  export interface MaxKeyExtended {
3
5
  $maxKey: 1;
@@ -13,8 +15,8 @@ export class MaxKey {
13
15
  return 'MaxKey';
14
16
  }
15
17
  /** @internal */
16
- get [Symbol.for('@@mdb.bson.version')](): 5 {
17
- return 5;
18
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
19
+ return BSON_MAJOR_VERSION;
18
20
  }
19
21
 
20
22
  /** @internal */
package/src/min_key.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { BSON_MAJOR_VERSION } from './constants';
2
+
1
3
  /** @public */
2
4
  export interface MinKeyExtended {
3
5
  $minKey: 1;
@@ -13,8 +15,8 @@ export class MinKey {
13
15
  return 'MinKey';
14
16
  }
15
17
  /** @internal */
16
- get [Symbol.for('@@mdb.bson.version')](): 5 {
17
- return 5;
18
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
19
+ return BSON_MAJOR_VERSION;
18
20
  }
19
21
 
20
22
  /** @internal */
package/src/objectid.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { BSONTypeError } from './error';
1
+ import { BSON_MAJOR_VERSION } from './constants';
2
+ import { BSONError } from './error';
2
3
  import { isUint8Array } from './parser/utils';
3
4
  import { BSONDataView, ByteUtils } from './utils/byte_utils';
4
5
 
@@ -32,8 +33,8 @@ export class ObjectId {
32
33
  return 'ObjectId';
33
34
  }
34
35
  /** @internal */
35
- get [Symbol.for('@@mdb.bson.version')](): 5 {
36
- return 5;
36
+ get [Symbol.for('@@mdb.bson.version')](): BSON_MAJOR_VERSION {
37
+ return BSON_MAJOR_VERSION;
37
38
  }
38
39
 
39
40
  /** @internal */
@@ -56,9 +57,7 @@ export class ObjectId {
56
57
  let workingId;
57
58
  if (typeof inputId === 'object' && inputId && 'id' in inputId) {
58
59
  if (typeof inputId.id !== 'string' && !ArrayBuffer.isView(inputId.id)) {
59
- throw new BSONTypeError(
60
- 'Argument passed in must have an id that is of type string or Buffer'
61
- );
60
+ throw new BSONError('Argument passed in must have an id that is of type string or Buffer');
62
61
  }
63
62
  if ('toHexString' in inputId && typeof inputId.toHexString === 'function') {
64
63
  workingId = ByteUtils.fromHex(inputId.toHexString());
@@ -84,17 +83,17 @@ export class ObjectId {
84
83
  if (bytes.byteLength === 12) {
85
84
  this[kId] = bytes;
86
85
  } else {
87
- throw new BSONTypeError('Argument passed in must be a string of 12 bytes');
86
+ throw new BSONError('Argument passed in must be a string of 12 bytes');
88
87
  }
89
88
  } else if (workingId.length === 24 && checkForHexRegExp.test(workingId)) {
90
89
  this[kId] = ByteUtils.fromHex(workingId);
91
90
  } else {
92
- throw new BSONTypeError(
91
+ throw new BSONError(
93
92
  'Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer'
94
93
  );
95
94
  }
96
95
  } else {
97
- throw new BSONTypeError('Argument passed in does not match the accepted types');
96
+ throw new BSONError('Argument passed in does not match the accepted types');
98
97
  }
99
98
  // If we are caching the hex string
100
99
  if (ObjectId.cacheHexString) {
@@ -270,7 +269,7 @@ export class ObjectId {
270
269
  static createFromHexString(hexString: string): ObjectId {
271
270
  // Throw an error if it's not a valid setup
272
271
  if (typeof hexString === 'undefined' || (hexString != null && hexString.length !== 24)) {
273
- throw new BSONTypeError(
272
+ throw new BSONError(
274
273
  'Argument passed in must be a single String of 12 bytes or a string of 24 hex characters'
275
274
  );
276
275
  }
@@ -1,5 +1,6 @@
1
1
  import { Binary } from '../binary';
2
2
  import type { Document } from '../bson';
3
+ import { BSONError } from '../error';
3
4
  import * as constants from '../constants';
4
5
  import { ByteUtils } from '../utils/byte_utils';
5
6
  import { isAnyArrayBuffer, isDate, isRegExp } from './utils';
@@ -77,7 +78,17 @@ function calculateElement(
77
78
  case 'boolean':
78
79
  return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (1 + 1);
79
80
  case 'object':
80
- if (value == null || value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
81
+ if (
82
+ value != null &&
83
+ typeof value._bsontype === 'string' &&
84
+ value[Symbol.for('@@mdb.bson.version')] !== constants.BSON_MAJOR_VERSION
85
+ ) {
86
+ throw new BSONError('Unsupported BSON version, bson types must be from bson 5.0 or later');
87
+ } else if (
88
+ value == null ||
89
+ value['_bsontype'] === 'MinKey' ||
90
+ value['_bsontype'] === 'MaxKey'
91
+ ) {
81
92
  return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + 1;
82
93
  } else if (value['_bsontype'] === 'ObjectId') {
83
94
  return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (12 + 1);
@@ -14,12 +14,14 @@ import { ObjectId } from '../objectid';
14
14
  import { BSONRegExp } from '../regexp';
15
15
  import { BSONSymbol } from '../symbol';
16
16
  import { Timestamp } from '../timestamp';
17
- import { ByteUtils } from '../utils/byte_utils';
17
+ import { BSONDataView, ByteUtils } from '../utils/byte_utils';
18
18
  import { validateUtf8 } from '../validate_utf8';
19
19
 
20
20
  /** @public */
21
21
  export interface DeserializeOptions {
22
- /** when deserializing a Long will fit it into a Number if it's smaller than 53 bits */
22
+ /** when deserializing a Long will return as a BigInt. */
23
+ useBigInt64?: boolean;
24
+ /** when deserializing a Long will fit it into a Number if it's smaller than 53 bits. */
23
25
  promoteLongs?: boolean;
24
26
  /** when deserializing a Binary will return it as a node.js Buffer instance. */
25
27
  promoteBuffers?: boolean;
@@ -29,7 +31,7 @@ export interface DeserializeOptions {
29
31
  fieldsAsRaw?: Document;
30
32
  /** return BSON regular expressions as BSONRegExp instances. */
31
33
  bsonRegExp?: boolean;
32
- /** allows the buffer to be larger than the parsed BSON object */
34
+ /** allows the buffer to be larger than the parsed BSON object. */
33
35
  allowObjectSmallerThanBufferSize?: boolean;
34
36
  /** Offset into buffer to begin reading document from */
35
37
  index?: number;
@@ -96,7 +98,7 @@ export function internalDeserialize(
96
98
  );
97
99
  }
98
100
 
99
- // Start deserializtion
101
+ // Start deserialization
100
102
  return deserializeObject(buffer, index, options, isArray);
101
103
  }
102
104
 
@@ -117,9 +119,18 @@ function deserializeObject(
117
119
  const bsonRegExp = typeof options['bsonRegExp'] === 'boolean' ? options['bsonRegExp'] : false;
118
120
 
119
121
  // Controls the promotion of values vs wrapper classes
120
- const promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers'];
121
- const promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs'];
122
- const promoteValues = options['promoteValues'] == null ? true : options['promoteValues'];
122
+ const promoteBuffers = options.promoteBuffers ?? false;
123
+ const promoteLongs = options.promoteLongs ?? true;
124
+ const promoteValues = options.promoteValues ?? true;
125
+ const useBigInt64 = options.useBigInt64 ?? false;
126
+
127
+ if (useBigInt64 && !promoteValues) {
128
+ throw new BSONError('Must either request bigint or Long for int64 deserialization');
129
+ }
130
+
131
+ if (useBigInt64 && !promoteLongs) {
132
+ throw new BSONError('Must either request bigint or Long for int64 deserialization');
133
+ }
123
134
 
124
135
  // Ensures default validation option if none given
125
136
  const validation = options.validation == null ? { utf8: true } : options.validation;
@@ -323,6 +334,8 @@ function deserializeObject(
323
334
  value = null;
324
335
  } else if (elementType === constants.BSON_DATA_LONG) {
325
336
  // Unpack the low and high bits
337
+ const dataview = BSONDataView.fromUint8Array(buffer.subarray(index, index + 8));
338
+
326
339
  const lowBits =
327
340
  buffer[index++] |
328
341
  (buffer[index++] << 8) |
@@ -334,8 +347,10 @@ function deserializeObject(
334
347
  (buffer[index++] << 16) |
335
348
  (buffer[index++] << 24);
336
349
  const long = new Long(lowBits, highBits);
337
- // Promote the long if possible
338
- if (promoteLongs && promoteValues === true) {
350
+ if (useBigInt64) {
351
+ value = dataview.getBigInt64(0, true);
352
+ } else if (promoteLongs && promoteValues === true) {
353
+ // Promote the long if possible
339
354
  value =
340
355
  long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
341
356
  ? long.toNumber()