bson 6.6.0 → 6.7.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/bson.rn.cjs CHANGED
@@ -150,41 +150,21 @@ class BSONOffsetError extends BSONError {
150
150
  }
151
151
  }
152
152
 
153
- const FIRST_BIT = 0x80;
154
- const FIRST_TWO_BITS = 0xc0;
155
- const FIRST_THREE_BITS = 0xe0;
156
- const FIRST_FOUR_BITS = 0xf0;
157
- const FIRST_FIVE_BITS = 0xf8;
158
- const TWO_BIT_CHAR = 0xc0;
159
- const THREE_BIT_CHAR = 0xe0;
160
- const FOUR_BIT_CHAR = 0xf0;
161
- const CONTINUING_CHAR = 0x80;
162
- function validateUtf8(bytes, start, end) {
163
- let continuation = 0;
164
- for (let i = start; i < end; i += 1) {
165
- const byte = bytes[i];
166
- if (continuation) {
167
- if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
168
- return false;
169
- }
170
- continuation -= 1;
153
+ const { TextDecoder } = require('../vendor/text-encoding');
154
+ let TextDecoderFatal;
155
+ let TextDecoderNonFatal;
156
+ function parseUtf8(buffer, start, end, fatal) {
157
+ if (fatal) {
158
+ TextDecoderFatal ??= new TextDecoder('utf8', { fatal: true });
159
+ try {
160
+ return TextDecoderFatal.decode(buffer.subarray(start, end));
171
161
  }
172
- else if (byte & FIRST_BIT) {
173
- if ((byte & FIRST_THREE_BITS) === TWO_BIT_CHAR) {
174
- continuation = 1;
175
- }
176
- else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
177
- continuation = 2;
178
- }
179
- else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
180
- continuation = 3;
181
- }
182
- else {
183
- return false;
184
- }
162
+ catch (cause) {
163
+ throw new BSONError('Invalid UTF-8 string in BSON document', { cause });
185
164
  }
186
165
  }
187
- return !continuation;
166
+ TextDecoderNonFatal ??= new TextDecoder('utf8', { fatal: false });
167
+ return TextDecoderNonFatal.decode(buffer.subarray(start, end));
188
168
  }
189
169
 
190
170
  function tryReadBasicLatin(uint8array, start, end) {
@@ -305,9 +285,7 @@ const nodeJsByteUtils = {
305
285
  if (fatal) {
306
286
  for (let i = 0; i < string.length; i++) {
307
287
  if (string.charCodeAt(i) === 0xfffd) {
308
- if (!validateUtf8(buffer, start, end)) {
309
- throw new BSONError('Invalid UTF-8 string in BSON document');
310
- }
288
+ parseUtf8(buffer, start, end, true);
311
289
  break;
312
290
  }
313
291
  }
@@ -327,7 +305,7 @@ const nodeJsByteUtils = {
327
305
  randomBytes: nodejsRandomBytes
328
306
  };
329
307
 
330
- const { TextEncoder, TextDecoder } = require('../vendor/text-encoding');
308
+ const { TextEncoder } = require('../vendor/text-encoding');
331
309
  const { encode: btoa, decode: atob } = require('../vendor/base64');
332
310
  function isReactNative() {
333
311
  const { navigator } = globalThis;
@@ -433,15 +411,7 @@ const webByteUtils = {
433
411
  if (basicLatin != null) {
434
412
  return basicLatin;
435
413
  }
436
- if (fatal) {
437
- try {
438
- return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
439
- }
440
- catch (cause) {
441
- throw new BSONError('Invalid UTF-8 string in BSON document', { cause });
442
- }
443
- }
444
- return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
414
+ return parseUtf8(uint8array, start, end, fatal);
445
415
  },
446
416
  utf8ByteLength(input) {
447
417
  return new TextEncoder().encode(input).byteLength;
@@ -854,6 +824,32 @@ class DBRef extends BSONValue {
854
824
  }
855
825
  }
856
826
 
827
+ function removeLeadingZerosAndExplicitPlus(str) {
828
+ if (str === '') {
829
+ return str;
830
+ }
831
+ let startIndex = 0;
832
+ const isNegative = str[startIndex] === '-';
833
+ const isExplicitlyPositive = str[startIndex] === '+';
834
+ if (isExplicitlyPositive || isNegative) {
835
+ startIndex += 1;
836
+ }
837
+ let foundInsignificantZero = false;
838
+ for (; startIndex < str.length && str[startIndex] === '0'; ++startIndex) {
839
+ foundInsignificantZero = true;
840
+ }
841
+ if (!foundInsignificantZero) {
842
+ return isExplicitlyPositive ? str.slice(1) : str;
843
+ }
844
+ return `${isNegative ? '-' : ''}${str.length === startIndex ? '0' : str.slice(startIndex)}`;
845
+ }
846
+ function validateStringCharacters(str, radix) {
847
+ radix = radix ?? 10;
848
+ const validCharacters = '0123456789abcdefghijklmnopqrstuvwxyz'.slice(0, radix);
849
+ const regex = new RegExp(`[^-+${validCharacters}]`, 'i');
850
+ return regex.test(str) ? false : str;
851
+ }
852
+
857
853
  let wasm = undefined;
858
854
  try {
859
855
  wasm = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 13, 2, 96, 0, 1, 127, 96, 4, 127, 127, 127, 127, 1, 127, 3, 7, 6, 0, 1, 1, 1, 1, 1, 6, 6, 1, 127, 1, 65, 0, 11, 7, 50, 6, 3, 109, 117, 108, 0, 1, 5, 100, 105, 118, 95, 115, 0, 2, 5, 100, 105, 118, 95, 117, 0, 3, 5, 114, 101, 109, 95, 115, 0, 4, 5, 114, 101, 109, 95, 117, 0, 5, 8, 103, 101, 116, 95, 104, 105, 103, 104, 0, 0, 10, 191, 1, 6, 4, 0, 35, 0, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 126, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 127, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 128, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 129, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 130, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11])), {}).exports;
@@ -942,25 +938,16 @@ class Long extends BSONValue {
942
938
  static fromBigInt(value, unsigned) {
943
939
  return Long.fromString(value.toString(), unsigned);
944
940
  }
945
- static fromString(str, unsigned, radix) {
941
+ static _fromString(str, unsigned, radix) {
946
942
  if (str.length === 0)
947
943
  throw new BSONError('empty string');
948
- if (str === 'NaN' || str === 'Infinity' || str === '+Infinity' || str === '-Infinity')
949
- return Long.ZERO;
950
- if (typeof unsigned === 'number') {
951
- (radix = unsigned), (unsigned = false);
952
- }
953
- else {
954
- unsigned = !!unsigned;
955
- }
956
- radix = radix || 10;
957
944
  if (radix < 2 || 36 < radix)
958
945
  throw new BSONError('radix');
959
946
  let p;
960
947
  if ((p = str.indexOf('-')) > 0)
961
948
  throw new BSONError('interior hyphen');
962
949
  else if (p === 0) {
963
- return Long.fromString(str.substring(1), unsigned, radix).neg();
950
+ return Long._fromString(str.substring(1), unsigned, radix).neg();
964
951
  }
965
952
  const radixToPower = Long.fromNumber(Math.pow(radix, 8));
966
953
  let result = Long.ZERO;
@@ -978,6 +965,45 @@ class Long extends BSONValue {
978
965
  result.unsigned = unsigned;
979
966
  return result;
980
967
  }
968
+ static fromStringStrict(str, unsignedOrRadix, radix) {
969
+ let unsigned = false;
970
+ if (typeof unsignedOrRadix === 'number') {
971
+ (radix = unsignedOrRadix), (unsignedOrRadix = false);
972
+ }
973
+ else {
974
+ unsigned = !!unsignedOrRadix;
975
+ }
976
+ radix ??= 10;
977
+ if (str.trim() !== str) {
978
+ throw new BSONError(`Input: '${str}' contains leading and/or trailing whitespace`);
979
+ }
980
+ if (!validateStringCharacters(str, radix)) {
981
+ throw new BSONError(`Input: '${str}' contains invalid characters for radix: ${radix}`);
982
+ }
983
+ const cleanedStr = removeLeadingZerosAndExplicitPlus(str);
984
+ const result = Long._fromString(cleanedStr, unsigned, radix);
985
+ if (result.toString(radix).toLowerCase() !== cleanedStr.toLowerCase()) {
986
+ throw new BSONError(`Input: ${str} is not representable as ${result.unsigned ? 'an unsigned' : 'a signed'} 64-bit Long ${radix != null ? `with radix: ${radix}` : ''}`);
987
+ }
988
+ return result;
989
+ }
990
+ static fromString(str, unsignedOrRadix, radix) {
991
+ let unsigned = false;
992
+ if (typeof unsignedOrRadix === 'number') {
993
+ (radix = unsignedOrRadix), (unsignedOrRadix = false);
994
+ }
995
+ else {
996
+ unsigned = !!unsignedOrRadix;
997
+ }
998
+ radix ??= 10;
999
+ if (str === 'NaN' && radix < 24) {
1000
+ return Long.ZERO;
1001
+ }
1002
+ else if ((str === 'Infinity' || str === '+Infinity' || str === '-Infinity') && radix < 35) {
1003
+ return Long.ZERO;
1004
+ }
1005
+ return Long._fromString(str, unsigned, radix);
1006
+ }
981
1007
  static fromBytes(bytes, unsigned, le) {
982
1008
  return le ? Long.fromBytesLE(bytes, unsigned) : Long.fromBytesBE(bytes, unsigned);
983
1009
  }
@@ -2055,6 +2081,28 @@ class Double extends BSONValue {
2055
2081
  }
2056
2082
  this.value = +value;
2057
2083
  }
2084
+ static fromString(value) {
2085
+ const coercedValue = Number(value);
2086
+ if (value === 'NaN')
2087
+ return new Double(NaN);
2088
+ if (value === 'Infinity')
2089
+ return new Double(Infinity);
2090
+ if (value === '-Infinity')
2091
+ return new Double(-Infinity);
2092
+ if (!Number.isFinite(coercedValue)) {
2093
+ throw new BSONError(`Input: ${value} is not representable as a Double`);
2094
+ }
2095
+ if (value.trim() !== value) {
2096
+ throw new BSONError(`Input: '${value}' contains whitespace`);
2097
+ }
2098
+ if (value === '') {
2099
+ throw new BSONError(`Input is an empty string`);
2100
+ }
2101
+ if (/[^-0-9.+eE]/.test(value)) {
2102
+ throw new BSONError(`Input: '${value}' is not in decimal or exponential notation`);
2103
+ }
2104
+ return new Double(coercedValue);
2105
+ }
2058
2106
  valueOf() {
2059
2107
  return this.value;
2060
2108
  }
@@ -2096,6 +2144,23 @@ class Int32 extends BSONValue {
2096
2144
  }
2097
2145
  this.value = +value | 0;
2098
2146
  }
2147
+ static fromString(value) {
2148
+ const cleanedValue = removeLeadingZerosAndExplicitPlus(value);
2149
+ const coercedValue = Number(value);
2150
+ if (BSON_INT32_MAX < coercedValue) {
2151
+ throw new BSONError(`Input: '${value}' is larger than the maximum value for Int32`);
2152
+ }
2153
+ else if (BSON_INT32_MIN > coercedValue) {
2154
+ throw new BSONError(`Input: '${value}' is smaller than the minimum value for Int32`);
2155
+ }
2156
+ else if (!Number.isSafeInteger(coercedValue)) {
2157
+ throw new BSONError(`Input: '${value}' is not a safe integer`);
2158
+ }
2159
+ else if (coercedValue.toString() !== cleanedValue) {
2160
+ throw new BSONError(`Input: '${value}' is not a valid Int32 string`);
2161
+ }
2162
+ return new Int32(coercedValue);
2163
+ }
2099
2164
  valueOf() {
2100
2165
  return this.value;
2101
2166
  }
@@ -3183,12 +3248,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
3183
3248
  stringSize > buffer.length - index ||
3184
3249
  buffer[index + stringSize - 1] !== 0)
3185
3250
  throw new BSONError('bad string length in bson');
3186
- if (validation != null && validation.utf8) {
3187
- if (!validateUtf8(buffer, index, index + stringSize - 1)) {
3188
- throw new BSONError('Invalid UTF-8 string in BSON document');
3189
- }
3190
- }
3191
- const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, false);
3251
+ const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
3192
3252
  index = index + stringSize;
3193
3253
  const oidBuffer = ByteUtils.allocateUnsafe(12);
3194
3254
  for (let i = 0; i < 12; i++)