bson 5.3.0 → 6.0.0-alpha

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 (73) hide show
  1. package/README.md +51 -43
  2. package/bson.d.ts +10 -23
  3. package/lib/bson.bundle.js +73 -130
  4. package/lib/bson.bundle.js.map +1 -1
  5. package/lib/bson.cjs +73 -130
  6. package/lib/bson.cjs.map +1 -1
  7. package/lib/bson.mjs +73 -130
  8. package/lib/bson.mjs.map +1 -1
  9. package/lib/bson.rn.cjs +4051 -0
  10. package/lib/bson.rn.cjs.map +1 -0
  11. package/package.json +26 -24
  12. package/src/binary.ts +19 -53
  13. package/src/bson.ts +2 -2
  14. package/src/code.ts +1 -1
  15. package/src/constants.ts +1 -1
  16. package/src/decimal128.ts +35 -67
  17. package/src/objectid.ts +20 -37
  18. package/src/parser/deserializer.ts +8 -8
  19. package/src/symbol.ts +1 -1
  20. package/src/timestamp.ts +7 -5
  21. package/src/utils/byte_utils.ts +2 -2
  22. package/src/utils/node_byte_utils.ts +3 -3
  23. package/src/utils/web_byte_utils.ts +2 -2
  24. package/vendor/base64/LICENSE-MIT.txt +20 -0
  25. package/vendor/base64/README.md +112 -0
  26. package/vendor/base64/base64.js +157 -0
  27. package/vendor/base64/package.json +43 -0
  28. package/vendor/text-encoding/LICENSE.md +237 -0
  29. package/vendor/text-encoding/README.md +111 -0
  30. package/vendor/text-encoding/index.js +9 -0
  31. package/vendor/text-encoding/lib/encoding-indexes.js +47 -0
  32. package/vendor/text-encoding/lib/encoding.js +3301 -0
  33. package/vendor/text-encoding/package.json +37 -0
  34. package/lib/binary.d.ts +0 -182
  35. package/lib/binary.d.ts.map +0 -1
  36. package/lib/bson.d.ts +0 -97
  37. package/lib/bson.d.ts.map +0 -1
  38. package/lib/bson_value.d.ts +0 -10
  39. package/lib/bson_value.d.ts.map +0 -1
  40. package/lib/code.d.ts +0 -32
  41. package/lib/code.d.ts.map +0 -1
  42. package/lib/constants.d.ts +0 -107
  43. package/lib/constants.d.ts.map +0 -1
  44. package/lib/db_ref.d.ts +0 -40
  45. package/lib/db_ref.d.ts.map +0 -1
  46. package/lib/decimal128.d.ts +0 -34
  47. package/lib/decimal128.d.ts.map +0 -1
  48. package/lib/double.d.ts +0 -35
  49. package/lib/double.d.ts.map +0 -1
  50. package/lib/error.d.ts +0 -50
  51. package/lib/error.d.ts.map +0 -1
  52. package/lib/extended_json.d.ts +0 -82
  53. package/lib/extended_json.d.ts.map +0 -1
  54. package/lib/index.d.ts +0 -4
  55. package/lib/index.d.ts.map +0 -1
  56. package/lib/int_32.d.ts +0 -35
  57. package/lib/int_32.d.ts.map +0 -1
  58. package/lib/long.d.ts +0 -323
  59. package/lib/long.d.ts.map +0 -1
  60. package/lib/max_key.d.ts +0 -19
  61. package/lib/max_key.d.ts.map +0 -1
  62. package/lib/min_key.d.ts +0 -19
  63. package/lib/min_key.d.ts.map +0 -1
  64. package/lib/objectid.d.ts +0 -96
  65. package/lib/objectid.d.ts.map +0 -1
  66. package/lib/regexp.d.ts +0 -36
  67. package/lib/regexp.d.ts.map +0 -1
  68. package/lib/symbol.d.ts +0 -28
  69. package/lib/symbol.d.ts.map +0 -1
  70. package/lib/timestamp.d.ts +0 -66
  71. package/lib/timestamp.d.ts.map +0 -1
  72. package/lib/validate_utf8.d.ts +0 -10
  73. package/lib/validate_utf8.d.ts.map +0 -1
package/src/binary.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { isUint8Array } from './parser/utils';
1
+ import { isAnyArrayBuffer, isUint8Array } from './parser/utils';
2
2
  import type { EJSONOptions } from './extended_json';
3
3
  import { BSONError } from './error';
4
4
  import { BSON_BINARY_SUBTYPE_UUID_NEW } from './constants';
@@ -65,27 +65,19 @@ export class Binary extends BSONValue {
65
65
 
66
66
  /**
67
67
  * Create a new Binary instance.
68
- *
69
- * This constructor can accept a string as its first argument. In this case,
70
- * this string will be encoded using ISO-8859-1, **not** using UTF-8.
71
- * This is almost certainly not what you want. Use `new Binary(Buffer.from(string))`
72
- * instead to convert the string to a Buffer using UTF-8 first.
73
- *
74
68
  * @param buffer - a buffer object containing the binary data.
75
69
  * @param subType - the option binary type.
76
70
  */
77
- constructor(buffer?: string | BinarySequence, subType?: number) {
71
+ constructor(buffer?: BinarySequence, subType?: number) {
78
72
  super();
79
73
  if (
80
74
  !(buffer == null) &&
81
- !(typeof buffer === 'string') &&
75
+ typeof buffer === 'string' &&
82
76
  !ArrayBuffer.isView(buffer) &&
83
- !(buffer instanceof ArrayBuffer) &&
77
+ !isAnyArrayBuffer(buffer) &&
84
78
  !Array.isArray(buffer)
85
79
  ) {
86
- throw new BSONError(
87
- 'Binary can only be constructed from string, Buffer, TypedArray, or Array<number>'
88
- );
80
+ throw new BSONError('Binary can only be constructed from Uint8Array or number[]');
89
81
  }
90
82
 
91
83
  this.sub_type = subType ?? Binary.BSON_BINARY_SUBTYPE_DEFAULT;
@@ -95,17 +87,9 @@ export class Binary extends BSONValue {
95
87
  this.buffer = ByteUtils.allocate(Binary.BUFFER_SIZE);
96
88
  this.position = 0;
97
89
  } else {
98
- if (typeof buffer === 'string') {
99
- // string
100
- this.buffer = ByteUtils.fromISO88591(buffer);
101
- } else if (Array.isArray(buffer)) {
102
- // number[]
103
- this.buffer = ByteUtils.fromNumberArray(buffer);
104
- } else {
105
- // Buffer | TypedArray | ArrayBuffer
106
- this.buffer = ByteUtils.toLocalBufferType(buffer);
107
- }
108
-
90
+ this.buffer = Array.isArray(buffer)
91
+ ? ByteUtils.fromNumberArray(buffer)
92
+ : ByteUtils.toLocalBufferType(buffer);
109
93
  this.position = this.buffer.byteLength;
110
94
  }
111
95
  }
@@ -147,12 +131,12 @@ export class Binary extends BSONValue {
147
131
  }
148
132
 
149
133
  /**
150
- * Writes a buffer or string to the binary.
134
+ * Writes a buffer to the binary.
151
135
  *
152
136
  * @param sequence - a string or buffer to be written to the Binary BSON object.
153
137
  * @param offset - specify the binary of where to write the content.
154
138
  */
155
- write(sequence: string | BinarySequence, offset: number): void {
139
+ write(sequence: BinarySequence, offset: number): void {
156
140
  offset = typeof offset === 'number' ? offset : this.position;
157
141
 
158
142
  // If the buffer is to small let's extend the buffer
@@ -169,10 +153,7 @@ export class Binary extends BSONValue {
169
153
  this.position =
170
154
  offset + sequence.byteLength > this.position ? offset + sequence.length : this.position;
171
155
  } else if (typeof sequence === 'string') {
172
- const bytes = ByteUtils.fromISO88591(sequence);
173
- this.buffer.set(bytes, offset);
174
- this.position =
175
- offset + sequence.length > this.position ? offset + sequence.length : this.position;
156
+ throw new BSONError('input cannot be string');
176
157
  }
177
158
  }
178
159
 
@@ -189,26 +170,12 @@ export class Binary extends BSONValue {
189
170
  return this.buffer.slice(position, position + length);
190
171
  }
191
172
 
192
- /**
193
- * Returns the value of this binary as a string.
194
- * @param asRaw - Will skip converting to a string
195
- * @remarks
196
- * This is handy when calling this function conditionally for some key value pairs and not others
197
- */
198
- value(asRaw?: boolean): string | BinarySequence {
199
- asRaw = !!asRaw;
200
-
173
+ /** returns a view of the binary value as a Uint8Array */
174
+ value(): Uint8Array {
201
175
  // Optimize to serialize for the situation where the data == size of buffer
202
- if (asRaw && this.buffer.length === this.position) {
203
- return this.buffer;
204
- }
205
-
206
- // If it's a node.js buffer object
207
- if (asRaw) {
208
- return this.buffer.slice(0, this.position);
209
- }
210
- // TODO(NODE-4361): remove binary string support, value(true) should be the default / only option here.
211
- return ByteUtils.toISO88591(this.buffer.subarray(0, this.position));
176
+ return this.buffer.length === this.position
177
+ ? this.buffer
178
+ : this.buffer.subarray(0, this.position);
212
179
  }
213
180
 
214
181
  /** the length of the binary sequence */
@@ -223,8 +190,9 @@ export class Binary extends BSONValue {
223
190
  toString(encoding?: 'hex' | 'base64' | 'utf8' | 'utf-8'): string {
224
191
  if (encoding === 'hex') return ByteUtils.toHex(this.buffer);
225
192
  if (encoding === 'base64') return ByteUtils.toBase64(this.buffer);
226
- if (encoding === 'utf8' || encoding === 'utf-8') return ByteUtils.toUTF8(this.buffer);
227
- return ByteUtils.toUTF8(this.buffer);
193
+ if (encoding === 'utf8' || encoding === 'utf-8')
194
+ return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
195
+ return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
228
196
  }
229
197
 
230
198
  /** @internal */
@@ -320,8 +288,6 @@ const UUID_WITH_DASHES = /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A
320
288
  * @public
321
289
  */
322
290
  export class UUID extends Binary {
323
- /** @deprecated Hex string is no longer cached, this control will be removed in a future major release */
324
- static cacheHexString = false;
325
291
  /**
326
292
  * Create a UUID type
327
293
  *
package/src/bson.ts CHANGED
@@ -10,8 +10,8 @@ import { MinKey } from './min_key';
10
10
  import { ObjectId } from './objectid';
11
11
  import { internalCalculateObjectSize } from './parser/calculate_size';
12
12
  // Parts of the parser
13
- import { internalDeserialize, DeserializeOptions } from './parser/deserializer';
14
- import { serializeInto, SerializeOptions } from './parser/serializer';
13
+ import { internalDeserialize, type DeserializeOptions } from './parser/deserializer';
14
+ import { serializeInto, type SerializeOptions } from './parser/serializer';
15
15
  import { BSONRegExp } from './regexp';
16
16
  import { BSONSymbol } from './symbol';
17
17
  import { Timestamp } from './timestamp';
package/src/code.ts CHANGED
@@ -62,7 +62,7 @@ export class Code extends BSONValue {
62
62
 
63
63
  inspect(): string {
64
64
  const codeJson = this.toJSON();
65
- return `new Code("${String(codeJson.code)}"${
65
+ return `new Code(${JSON.stringify(String(codeJson.code))}${
66
66
  codeJson.scope != null ? `, ${JSON.stringify(codeJson.scope)}` : ''
67
67
  })`;
68
68
  }
package/src/constants.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** @internal */
2
- export const BSON_MAJOR_VERSION = 5 as const;
2
+ export const BSON_MAJOR_VERSION = 6 as const;
3
3
 
4
4
  /** @internal */
5
5
  export const BSON_INT32_MAX = 0x7fffffff;
package/src/decimal128.ts CHANGED
@@ -160,6 +160,7 @@ export class Decimal128 extends BSONValue {
160
160
  static fromString(representation: string): Decimal128 {
161
161
  // Parse state tracking
162
162
  let isNegative = false;
163
+ let sawSign = false;
163
164
  let sawRadix = false;
164
165
  let foundNonZero = false;
165
166
 
@@ -180,15 +181,11 @@ export class Decimal128 extends BSONValue {
180
181
  let nDigitsStored = 0;
181
182
  // Insertion pointer for digits
182
183
  let digitsInsert = 0;
183
- // The index of the first non-zero digit
184
- let firstDigit = 0;
185
184
  // The index of the last digit
186
185
  let lastDigit = 0;
187
186
 
188
187
  // Exponent
189
188
  let exponent = 0;
190
- // loop index over array
191
- let i = 0;
192
189
  // The high 17 digits of the significand
193
190
  let significandHigh = new Long(0, 0);
194
191
  // The low 17 digits of the significand
@@ -241,6 +238,7 @@ export class Decimal128 extends BSONValue {
241
238
 
242
239
  // Get the negative or positive sign
243
240
  if (representation[index] === '+' || representation[index] === '-') {
241
+ sawSign = true;
244
242
  isNegative = representation[index++] === '-';
245
243
  }
246
244
 
@@ -263,7 +261,7 @@ export class Decimal128 extends BSONValue {
263
261
  continue;
264
262
  }
265
263
 
266
- if (nDigitsStored < 34) {
264
+ if (nDigitsStored < MAX_DIGITS) {
267
265
  if (representation[index] !== '0' || foundNonZero) {
268
266
  if (!foundNonZero) {
269
267
  firstNonZero = nDigitsRead;
@@ -307,11 +305,7 @@ export class Decimal128 extends BSONValue {
307
305
 
308
306
  // Done reading input
309
307
  // Find first non-zero digit in digits
310
- firstDigit = 0;
311
-
312
308
  if (!nDigitsStored) {
313
- firstDigit = 0;
314
- lastDigit = 0;
315
309
  digits[0] = 0;
316
310
  nDigits = 1;
317
311
  nDigitsStored = 1;
@@ -320,7 +314,11 @@ export class Decimal128 extends BSONValue {
320
314
  lastDigit = nDigitsStored - 1;
321
315
  significantDigits = nDigits;
322
316
  if (significantDigits !== 1) {
323
- while (digits[firstNonZero + significantDigits - 1] === 0) {
317
+ while (
318
+ representation[
319
+ firstNonZero + significantDigits - 1 + Number(sawSign) + Number(sawRadix)
320
+ ] === '0'
321
+ ) {
324
322
  significantDigits = significantDigits - 1;
325
323
  }
326
324
  }
@@ -331,7 +329,7 @@ export class Decimal128 extends BSONValue {
331
329
  // to represent user input
332
330
 
333
331
  // Overflow prevention
334
- if (exponent <= radixPosition && radixPosition - exponent > 1 << 14) {
332
+ if (exponent <= radixPosition && radixPosition > exponent + (1 << 14)) {
335
333
  exponent = EXPONENT_MIN;
336
334
  } else {
337
335
  exponent = exponent - radixPosition;
@@ -341,11 +339,9 @@ export class Decimal128 extends BSONValue {
341
339
  while (exponent > EXPONENT_MAX) {
342
340
  // Shift exponent to significand and decrease
343
341
  lastDigit = lastDigit + 1;
344
-
345
- if (lastDigit - firstDigit > MAX_DIGITS) {
342
+ if (lastDigit >= MAX_DIGITS) {
346
343
  // Check if we have a zero then just hard clamp, otherwise fail
347
- const digitsString = digits.join('');
348
- if (digitsString.match(/^0+$/)) {
344
+ if (significantDigits === 0) {
349
345
  exponent = EXPONENT_MAX;
350
346
  break;
351
347
  }
@@ -357,16 +353,28 @@ export class Decimal128 extends BSONValue {
357
353
 
358
354
  while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) {
359
355
  // Shift last digit. can only do this if < significant digits than # stored.
360
- if (lastDigit === 0 && significantDigits < nDigitsStored) {
361
- exponent = EXPONENT_MIN;
362
- significantDigits = 0;
363
- break;
356
+ if (lastDigit === 0) {
357
+ if (significantDigits === 0) {
358
+ exponent = EXPONENT_MIN;
359
+ break;
360
+ }
361
+
362
+ invalidErr(representation, 'exponent underflow');
364
363
  }
365
364
 
366
365
  if (nDigitsStored < nDigits) {
366
+ if (
367
+ representation[nDigits - 1 + Number(sawSign) + Number(sawRadix)] !== '0' &&
368
+ significantDigits !== 0
369
+ ) {
370
+ invalidErr(representation, 'inexact rounding');
371
+ }
367
372
  // adjust to match digits not stored
368
373
  nDigits = nDigits - 1;
369
374
  } else {
375
+ if (digits[lastDigit] !== 0) {
376
+ invalidErr(representation, 'inexact rounding');
377
+ }
370
378
  // adjust to round
371
379
  lastDigit = lastDigit - 1;
372
380
  }
@@ -374,68 +382,28 @@ export class Decimal128 extends BSONValue {
374
382
  if (exponent < EXPONENT_MAX) {
375
383
  exponent = exponent + 1;
376
384
  } else {
377
- // Check if we have a zero then just hard clamp, otherwise fail
378
- const digitsString = digits.join('');
379
- if (digitsString.match(/^0+$/)) {
380
- exponent = EXPONENT_MAX;
381
- break;
382
- }
383
385
  invalidErr(representation, 'overflow');
384
386
  }
385
387
  }
386
388
 
387
389
  // Round
388
390
  // We've normalized the exponent, but might still need to round.
389
- if (lastDigit - firstDigit + 1 < significantDigits) {
390
- let endOfString = nDigitsRead;
391
-
391
+ if (lastDigit + 1 < significantDigits) {
392
392
  // If we have seen a radix point, 'string' is 1 longer than we have
393
393
  // documented with ndigits_read, so inc the position of the first nonzero
394
394
  // digit and the position that digits are read to.
395
395
  if (sawRadix) {
396
396
  firstNonZero = firstNonZero + 1;
397
- endOfString = endOfString + 1;
398
397
  }
399
- // if negative, we need to increment again to account for - sign at start.
400
- if (isNegative) {
398
+ // if saw sign, we need to increment again to account for - or + sign at start.
399
+ if (sawSign) {
401
400
  firstNonZero = firstNonZero + 1;
402
- endOfString = endOfString + 1;
403
401
  }
404
402
 
405
403
  const roundDigit = parseInt(representation[firstNonZero + lastDigit + 1], 10);
406
- let roundBit = 0;
407
-
408
- if (roundDigit >= 5) {
409
- roundBit = 1;
410
- if (roundDigit === 5) {
411
- roundBit = digits[lastDigit] % 2 === 1 ? 1 : 0;
412
- for (i = firstNonZero + lastDigit + 2; i < endOfString; i++) {
413
- if (parseInt(representation[i], 10)) {
414
- roundBit = 1;
415
- break;
416
- }
417
- }
418
- }
419
- }
420
404
 
421
- if (roundBit) {
422
- let dIdx = lastDigit;
423
-
424
- for (; dIdx >= 0; dIdx--) {
425
- if (++digits[dIdx] > 9) {
426
- digits[dIdx] = 0;
427
-
428
- // overflowed most significant digit
429
- if (dIdx === 0) {
430
- if (exponent < EXPONENT_MAX) {
431
- exponent = exponent + 1;
432
- digits[dIdx] = 1;
433
- } else {
434
- return new Decimal128(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER);
435
- }
436
- }
437
- }
438
- }
405
+ if (roundDigit !== 0) {
406
+ invalidErr(representation, 'inexact rounding');
439
407
  }
440
408
  }
441
409
 
@@ -449,8 +417,8 @@ export class Decimal128 extends BSONValue {
449
417
  if (significantDigits === 0) {
450
418
  significandHigh = Long.fromNumber(0);
451
419
  significandLow = Long.fromNumber(0);
452
- } else if (lastDigit - firstDigit < 17) {
453
- let dIdx = firstDigit;
420
+ } else if (lastDigit < 17) {
421
+ let dIdx = 0;
454
422
  significandLow = Long.fromNumber(digits[dIdx++]);
455
423
  significandHigh = new Long(0, 0);
456
424
 
@@ -459,7 +427,7 @@ export class Decimal128 extends BSONValue {
459
427
  significandLow = significandLow.add(Long.fromNumber(digits[dIdx]));
460
428
  }
461
429
  } else {
462
- let dIdx = firstDigit;
430
+ let dIdx = 0;
463
431
  significandHigh = Long.fromNumber(digits[dIdx++]);
464
432
 
465
433
  for (; dIdx <= lastDigit - 17; dIdx++) {
package/src/objectid.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { BSONValue } from './bson_value';
2
2
  import { BSONError } from './error';
3
- import { isUint8Array } from './parser/utils';
4
3
  import { BSONDataView, ByteUtils } from './utils/byte_utils';
5
4
 
6
5
  // Regular expression that checks for hex value
@@ -74,19 +73,11 @@ export class ObjectId extends BSONValue {
74
73
  // If intstanceof matches we can escape calling ensure buffer in Node.js environments
75
74
  this[kId] = ByteUtils.toLocalBufferType(workingId);
76
75
  } else if (typeof workingId === 'string') {
77
- if (workingId.length === 12) {
78
- // TODO(NODE-4361): Remove string of length 12 support
79
- const bytes = ByteUtils.fromUTF8(workingId);
80
- if (bytes.byteLength === 12) {
81
- this[kId] = bytes;
82
- } else {
83
- throw new BSONError('Argument passed in must be a string of 12 bytes');
84
- }
85
- } else if (workingId.length === 24 && checkForHexRegExp.test(workingId)) {
76
+ if (workingId.length === 24 && checkForHexRegExp.test(workingId)) {
86
77
  this[kId] = ByteUtils.fromHex(workingId);
87
78
  } else {
88
79
  throw new BSONError(
89
- 'Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer'
80
+ 'input must be a 24 character hex string, 12 byte Uint8Array, or an integer'
90
81
  );
91
82
  }
92
83
  } else {
@@ -113,7 +104,7 @@ export class ObjectId extends BSONValue {
113
104
  }
114
105
  }
115
106
 
116
- /** Returns the ObjectId id as a 24 character hex string representation */
107
+ /** Returns the ObjectId id as a 24 lowercase character hex string representation */
117
108
  toHexString(): string {
118
109
  if (ObjectId.cacheHexString && this.__id) {
119
110
  return this.__id;
@@ -188,44 +179,37 @@ export class ObjectId extends BSONValue {
188
179
  return this.toHexString();
189
180
  }
190
181
 
182
+ /** @internal */
183
+ private static is(variable: unknown): variable is ObjectId {
184
+ return (
185
+ variable != null &&
186
+ typeof variable === 'object' &&
187
+ '_bsontype' in variable &&
188
+ variable._bsontype === 'ObjectId'
189
+ );
190
+ }
191
+
191
192
  /**
192
193
  * Compares the equality of this ObjectId with `otherID`.
193
194
  *
194
195
  * @param otherId - ObjectId instance to compare against.
195
196
  */
196
- equals(otherId: string | ObjectId | ObjectIdLike): boolean {
197
+ equals(otherId: string | ObjectId | ObjectIdLike | undefined | null): boolean {
197
198
  if (otherId === undefined || otherId === null) {
198
199
  return false;
199
200
  }
200
201
 
201
- if (otherId instanceof ObjectId) {
202
+ if (ObjectId.is(otherId)) {
202
203
  return this[kId][11] === otherId[kId][11] && ByteUtils.equals(this[kId], otherId[kId]);
203
204
  }
204
205
 
205
- if (
206
- typeof otherId === 'string' &&
207
- ObjectId.isValid(otherId) &&
208
- otherId.length === 12 &&
209
- isUint8Array(this.id)
210
- ) {
211
- return ByteUtils.equals(this.id, ByteUtils.fromISO88591(otherId));
212
- }
213
-
214
- if (typeof otherId === 'string' && ObjectId.isValid(otherId) && otherId.length === 24) {
206
+ if (typeof otherId === 'string') {
215
207
  return otherId.toLowerCase() === this.toHexString();
216
208
  }
217
209
 
218
- if (typeof otherId === 'string' && ObjectId.isValid(otherId) && otherId.length === 12) {
219
- return ByteUtils.equals(ByteUtils.fromUTF8(otherId), this.id);
220
- }
221
-
222
- if (
223
- typeof otherId === 'object' &&
224
- 'toHexString' in otherId &&
225
- typeof otherId.toHexString === 'function'
226
- ) {
210
+ if (typeof otherId === 'object' && typeof otherId.toHexString === 'function') {
227
211
  const otherIdString = otherId.toHexString();
228
- const thisIdString = this.toHexString().toLowerCase();
212
+ const thisIdString = this.toHexString();
229
213
  return typeof otherIdString === 'string' && otherIdString.toLowerCase() === thisIdString;
230
214
  }
231
215
 
@@ -281,9 +265,8 @@ export class ObjectId extends BSONValue {
281
265
  }
282
266
 
283
267
  /**
284
- * Checks if a value is a valid bson ObjectId
285
- *
286
- * @param id - ObjectId instance to validate.
268
+ * Checks if a value can be used to create a valid bson ObjectId
269
+ * @param id - any JS value
287
270
  */
288
271
  static isValid(id: string | number | ObjectId | ObjectIdLike | Uint8Array): boolean {
289
272
  if (id == null) return false;
@@ -2,7 +2,7 @@ import { Binary, UUID } from '../binary';
2
2
  import type { Document } from '../bson';
3
3
  import { Code } from '../code';
4
4
  import * as constants from '../constants';
5
- import { DBRef, DBRefLike, isDBRefLike } from '../db_ref';
5
+ import { DBRef, type DBRefLike, isDBRefLike } from '../db_ref';
6
6
  import { Decimal128 } from '../decimal128';
7
7
  import { Double } from '../double';
8
8
  import { BSONError } from '../error';
@@ -236,7 +236,7 @@ function deserializeObject(
236
236
  if (i >= buffer.byteLength) throw new BSONError('Bad BSON Document: illegal CString');
237
237
 
238
238
  // Represents the key
239
- const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer.subarray(index, i));
239
+ const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i);
240
240
 
241
241
  // shouldValidateKey is true if the key should be validated, false otherwise
242
242
  let shouldValidateKey = true;
@@ -476,7 +476,7 @@ function deserializeObject(
476
476
  // If are at the end of the buffer there is a problem with the document
477
477
  if (i >= buffer.length) throw new BSONError('Bad BSON Document: illegal CString');
478
478
  // Return the C string
479
- const source = ByteUtils.toUTF8(buffer.subarray(index, i));
479
+ const source = ByteUtils.toUTF8(buffer, index, i);
480
480
  // Create the regexp
481
481
  index = i + 1;
482
482
 
@@ -489,7 +489,7 @@ function deserializeObject(
489
489
  // If are at the end of the buffer there is a problem with the document
490
490
  if (i >= buffer.length) throw new BSONError('Bad BSON Document: illegal CString');
491
491
  // Return the C string
492
- const regExpOptions = ByteUtils.toUTF8(buffer.subarray(index, i));
492
+ const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
493
493
  index = i + 1;
494
494
 
495
495
  // For each option add the corresponding one for javascript
@@ -521,7 +521,7 @@ function deserializeObject(
521
521
  // If are at the end of the buffer there is a problem with the document
522
522
  if (i >= buffer.length) throw new BSONError('Bad BSON Document: illegal CString');
523
523
  // Return the C string
524
- const source = ByteUtils.toUTF8(buffer.subarray(index, i));
524
+ const source = ByteUtils.toUTF8(buffer, index, i);
525
525
  index = i + 1;
526
526
 
527
527
  // Get the start search index
@@ -533,7 +533,7 @@ function deserializeObject(
533
533
  // If are at the end of the buffer there is a problem with the document
534
534
  if (i >= buffer.length) throw new BSONError('Bad BSON Document: illegal CString');
535
535
  // Return the C string
536
- const regExpOptions = ByteUtils.toUTF8(buffer.subarray(index, i));
536
+ const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
537
537
  index = i + 1;
538
538
 
539
539
  // Set the object
@@ -678,7 +678,7 @@ function deserializeObject(
678
678
  throw new BSONError('Invalid UTF-8 string in BSON document');
679
679
  }
680
680
  }
681
- const namespace = ByteUtils.toUTF8(buffer.subarray(index, index + stringSize - 1));
681
+ const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1);
682
682
  // Update parse index position
683
683
  index = index + stringSize;
684
684
 
@@ -735,7 +735,7 @@ function getValidatedString(
735
735
  end: number,
736
736
  shouldValidateUtf8: boolean
737
737
  ) {
738
- const value = ByteUtils.toUTF8(buffer.subarray(start, end));
738
+ const value = ByteUtils.toUTF8(buffer, start, end);
739
739
  // if utf8 validation is on, do the check
740
740
  if (shouldValidateUtf8) {
741
741
  for (let i = 0; i < value.length; i++) {
package/src/symbol.ts CHANGED
@@ -34,7 +34,7 @@ export class BSONSymbol extends BSONValue {
34
34
  }
35
35
 
36
36
  inspect(): string {
37
- return `new BSONSymbol("${this.value}")`;
37
+ return `new BSONSymbol(${JSON.stringify(this.value)})`;
38
38
  }
39
39
 
40
40
  toJSON(): string {
package/src/timestamp.ts CHANGED
@@ -61,24 +61,26 @@ export class Timestamp extends LongWithoutOverridesClass {
61
61
  if (typeof low.i !== 'number' && (typeof low.i !== 'object' || low.i._bsontype !== 'Int32')) {
62
62
  throw new BSONError('Timestamp constructed from { t, i } must provide i as a number');
63
63
  }
64
- if (low.t < 0) {
64
+ const t = Number(low.t);
65
+ const i = Number(low.i);
66
+ if (t < 0 || Number.isNaN(t)) {
65
67
  throw new BSONError('Timestamp constructed from { t, i } must provide a positive t');
66
68
  }
67
- if (low.i < 0) {
69
+ if (i < 0 || Number.isNaN(i)) {
68
70
  throw new BSONError('Timestamp constructed from { t, i } must provide a positive i');
69
71
  }
70
- if (low.t > 0xffff_ffff) {
72
+ if (t > 0xffff_ffff) {
71
73
  throw new BSONError(
72
74
  'Timestamp constructed from { t, i } must provide t equal or less than uint32 max'
73
75
  );
74
76
  }
75
- if (low.i > 0xffff_ffff) {
77
+ if (i > 0xffff_ffff) {
76
78
  throw new BSONError(
77
79
  'Timestamp constructed from { t, i } must provide i equal or less than uint32 max'
78
80
  );
79
81
  }
80
82
 
81
- super(low.i.valueOf(), low.t.valueOf(), true);
83
+ super(i, t, true);
82
84
  } else {
83
85
  throw new BSONError(
84
86
  'A Timestamp can only be constructed with: bigint, Long, or { t: number; i: number }'
@@ -21,12 +21,12 @@ export type ByteUtils = {
21
21
  toISO88591: (buffer: Uint8Array) => string;
22
22
  /** Create a Uint8Array from a hex string */
23
23
  fromHex: (hex: string) => Uint8Array;
24
- /** Create a hex string from bytes */
24
+ /** Create a lowercase hex string from bytes */
25
25
  toHex: (buffer: Uint8Array) => string;
26
26
  /** Create a Uint8Array containing utf8 code units from a string */
27
27
  fromUTF8: (text: string) => Uint8Array;
28
28
  /** Create a string from utf8 code units */
29
- toUTF8: (buffer: Uint8Array) => string;
29
+ toUTF8: (buffer: Uint8Array, start: number, end: number) => string;
30
30
  /** Get the utf8 code unit count from a string if it were to be transformed to utf8 */
31
31
  utf8ByteLength: (input: string) => number;
32
32
  /** Encode UTF8 bytes generated from `source` string into `destination` at byteOffset. Returns the number of bytes encoded. */
@@ -5,7 +5,7 @@ type NodeJsBuffer = ArrayBufferView &
5
5
  Uint8Array & {
6
6
  write(string: string, offset: number, length: undefined, encoding: 'utf8'): number;
7
7
  copy(target: Uint8Array, targetStart: number, sourceStart: number, sourceEnd: number): number;
8
- toString: (this: Uint8Array, encoding: NodeJsEncoding) => string;
8
+ toString: (this: Uint8Array, encoding: NodeJsEncoding, start?: number, end?: number) => string;
9
9
  equals: (this: Uint8Array, other: Uint8Array) => boolean;
10
10
  };
11
11
  type NodeJsBufferConstructor = Omit<Uint8ArrayConstructor, 'from'> & {
@@ -125,8 +125,8 @@ export const nodeJsByteUtils = {
125
125
  return Buffer.from(text, 'utf8');
126
126
  },
127
127
 
128
- toUTF8(buffer: Uint8Array): string {
129
- return nodeJsByteUtils.toLocalBufferType(buffer).toString('utf8');
128
+ toUTF8(buffer: Uint8Array, start: number, end: number): string {
129
+ return nodeJsByteUtils.toLocalBufferType(buffer).toString('utf8', start, end);
130
130
  },
131
131
 
132
132
  utf8ByteLength(input: string): number {
@@ -172,8 +172,8 @@ export const webByteUtils = {
172
172
  return new TextEncoder().encode(text);
173
173
  },
174
174
 
175
- toUTF8(uint8array: Uint8Array): string {
176
- return new TextDecoder('utf8', { fatal: false }).decode(uint8array);
175
+ toUTF8(uint8array: Uint8Array, start: number, end: number): string {
176
+ return new TextDecoder('utf8', { fatal: false }).decode(uint8array.slice(start, end));
177
177
  },
178
178
 
179
179
  utf8ByteLength(input: string): number {
@@ -0,0 +1,20 @@
1
+ Copyright Mathias Bynens <https://mathiasbynens.be/>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.