bson 6.6.0 → 6.8.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/README.md +27 -0
- package/bson.d.ts +148 -7
- package/lib/bson.bundle.js +134 -74
- package/lib/bson.bundle.js.map +1 -1
- package/lib/bson.cjs +134 -74
- package/lib/bson.cjs.map +1 -1
- package/lib/bson.mjs +134 -74
- package/lib/bson.mjs.map +1 -1
- package/lib/bson.rn.cjs +136 -75
- package/lib/bson.rn.cjs.map +1 -1
- package/package.json +14 -15
- package/src/constants.ts +1 -1
- package/src/double.ts +36 -0
- package/src/int_32.ts +34 -0
- package/src/long.ts +211 -31
- package/src/parse_utf8.ts +35 -0
- package/src/parser/deserializer.ts +1 -7
- package/src/utils/node_byte_utils.ts +2 -5
- package/src/utils/string_utils.ts +44 -0
- package/src/utils/web_byte_utils.ts +2 -8
- package/src/validate_utf8.ts +0 -47
package/lib/bson.mjs
CHANGED
|
@@ -134,41 +134,20 @@ class BSONOffsetError extends BSONError {
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const FOUR_BIT_CHAR = 0xf0;
|
|
145
|
-
const CONTINUING_CHAR = 0x80;
|
|
146
|
-
function validateUtf8(bytes, start, end) {
|
|
147
|
-
let continuation = 0;
|
|
148
|
-
for (let i = start; i < end; i += 1) {
|
|
149
|
-
const byte = bytes[i];
|
|
150
|
-
if (continuation) {
|
|
151
|
-
if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
continuation -= 1;
|
|
137
|
+
let TextDecoderFatal;
|
|
138
|
+
let TextDecoderNonFatal;
|
|
139
|
+
function parseUtf8(buffer, start, end, fatal) {
|
|
140
|
+
if (fatal) {
|
|
141
|
+
TextDecoderFatal ??= new TextDecoder('utf8', { fatal: true });
|
|
142
|
+
try {
|
|
143
|
+
return TextDecoderFatal.decode(buffer.subarray(start, end));
|
|
155
144
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
continuation = 1;
|
|
159
|
-
}
|
|
160
|
-
else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
|
|
161
|
-
continuation = 2;
|
|
162
|
-
}
|
|
163
|
-
else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
|
|
164
|
-
continuation = 3;
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
145
|
+
catch (cause) {
|
|
146
|
+
throw new BSONError('Invalid UTF-8 string in BSON document', { cause });
|
|
169
147
|
}
|
|
170
148
|
}
|
|
171
|
-
|
|
149
|
+
TextDecoderNonFatal ??= new TextDecoder('utf8', { fatal: false });
|
|
150
|
+
return TextDecoderNonFatal.decode(buffer.subarray(start, end));
|
|
172
151
|
}
|
|
173
152
|
|
|
174
153
|
function tryReadBasicLatin(uint8array, start, end) {
|
|
@@ -289,9 +268,7 @@ const nodeJsByteUtils = {
|
|
|
289
268
|
if (fatal) {
|
|
290
269
|
for (let i = 0; i < string.length; i++) {
|
|
291
270
|
if (string.charCodeAt(i) === 0xfffd) {
|
|
292
|
-
|
|
293
|
-
throw new BSONError('Invalid UTF-8 string in BSON document');
|
|
294
|
-
}
|
|
271
|
+
parseUtf8(buffer, start, end, true);
|
|
295
272
|
break;
|
|
296
273
|
}
|
|
297
274
|
}
|
|
@@ -415,15 +392,7 @@ const webByteUtils = {
|
|
|
415
392
|
if (basicLatin != null) {
|
|
416
393
|
return basicLatin;
|
|
417
394
|
}
|
|
418
|
-
|
|
419
|
-
try {
|
|
420
|
-
return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
|
|
421
|
-
}
|
|
422
|
-
catch (cause) {
|
|
423
|
-
throw new BSONError('Invalid UTF-8 string in BSON document', { cause });
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
|
|
395
|
+
return parseUtf8(uint8array, start, end, fatal);
|
|
427
396
|
},
|
|
428
397
|
utf8ByteLength(input) {
|
|
429
398
|
return new TextEncoder().encode(input).byteLength;
|
|
@@ -836,6 +805,32 @@ class DBRef extends BSONValue {
|
|
|
836
805
|
}
|
|
837
806
|
}
|
|
838
807
|
|
|
808
|
+
function removeLeadingZerosAndExplicitPlus(str) {
|
|
809
|
+
if (str === '') {
|
|
810
|
+
return str;
|
|
811
|
+
}
|
|
812
|
+
let startIndex = 0;
|
|
813
|
+
const isNegative = str[startIndex] === '-';
|
|
814
|
+
const isExplicitlyPositive = str[startIndex] === '+';
|
|
815
|
+
if (isExplicitlyPositive || isNegative) {
|
|
816
|
+
startIndex += 1;
|
|
817
|
+
}
|
|
818
|
+
let foundInsignificantZero = false;
|
|
819
|
+
for (; startIndex < str.length && str[startIndex] === '0'; ++startIndex) {
|
|
820
|
+
foundInsignificantZero = true;
|
|
821
|
+
}
|
|
822
|
+
if (!foundInsignificantZero) {
|
|
823
|
+
return isExplicitlyPositive ? str.slice(1) : str;
|
|
824
|
+
}
|
|
825
|
+
return `${isNegative ? '-' : ''}${str.length === startIndex ? '0' : str.slice(startIndex)}`;
|
|
826
|
+
}
|
|
827
|
+
function validateStringCharacters(str, radix) {
|
|
828
|
+
radix = radix ?? 10;
|
|
829
|
+
const validCharacters = '0123456789abcdefghijklmnopqrstuvwxyz'.slice(0, radix);
|
|
830
|
+
const regex = new RegExp(`[^-+${validCharacters}]`, 'i');
|
|
831
|
+
return regex.test(str) ? false : str;
|
|
832
|
+
}
|
|
833
|
+
|
|
839
834
|
let wasm = undefined;
|
|
840
835
|
try {
|
|
841
836
|
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;
|
|
@@ -858,19 +853,18 @@ class Long extends BSONValue {
|
|
|
858
853
|
get __isLong__() {
|
|
859
854
|
return true;
|
|
860
855
|
}
|
|
861
|
-
constructor(
|
|
856
|
+
constructor(lowOrValue = 0, highOrUnsigned, unsigned) {
|
|
862
857
|
super();
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
}
|
|
858
|
+
const unsignedBool = typeof highOrUnsigned === 'boolean' ? highOrUnsigned : Boolean(unsigned);
|
|
859
|
+
const high = typeof highOrUnsigned === 'number' ? highOrUnsigned : 0;
|
|
860
|
+
const res = typeof lowOrValue === 'string'
|
|
861
|
+
? Long.fromString(lowOrValue, unsignedBool)
|
|
862
|
+
: typeof lowOrValue === 'bigint'
|
|
863
|
+
? Long.fromBigInt(lowOrValue, unsignedBool)
|
|
864
|
+
: { low: lowOrValue | 0, high: high | 0, unsigned: unsignedBool };
|
|
865
|
+
this.low = res.low;
|
|
866
|
+
this.high = res.high;
|
|
867
|
+
this.unsigned = res.unsigned;
|
|
874
868
|
}
|
|
875
869
|
static fromBits(lowBits, highBits, unsigned) {
|
|
876
870
|
return new Long(lowBits, highBits, unsigned);
|
|
@@ -922,27 +916,20 @@ class Long extends BSONValue {
|
|
|
922
916
|
return Long.fromBits(value % TWO_PWR_32_DBL | 0, (value / TWO_PWR_32_DBL) | 0, unsigned);
|
|
923
917
|
}
|
|
924
918
|
static fromBigInt(value, unsigned) {
|
|
925
|
-
|
|
919
|
+
const FROM_BIGINT_BIT_MASK = BigInt(0xffffffff);
|
|
920
|
+
const FROM_BIGINT_BIT_SHIFT = BigInt(32);
|
|
921
|
+
return new Long(Number(value & FROM_BIGINT_BIT_MASK), Number((value >> FROM_BIGINT_BIT_SHIFT) & FROM_BIGINT_BIT_MASK), unsigned);
|
|
926
922
|
}
|
|
927
|
-
static
|
|
923
|
+
static _fromString(str, unsigned, radix) {
|
|
928
924
|
if (str.length === 0)
|
|
929
925
|
throw new BSONError('empty string');
|
|
930
|
-
if (str === 'NaN' || str === 'Infinity' || str === '+Infinity' || str === '-Infinity')
|
|
931
|
-
return Long.ZERO;
|
|
932
|
-
if (typeof unsigned === 'number') {
|
|
933
|
-
(radix = unsigned), (unsigned = false);
|
|
934
|
-
}
|
|
935
|
-
else {
|
|
936
|
-
unsigned = !!unsigned;
|
|
937
|
-
}
|
|
938
|
-
radix = radix || 10;
|
|
939
926
|
if (radix < 2 || 36 < radix)
|
|
940
927
|
throw new BSONError('radix');
|
|
941
928
|
let p;
|
|
942
929
|
if ((p = str.indexOf('-')) > 0)
|
|
943
930
|
throw new BSONError('interior hyphen');
|
|
944
931
|
else if (p === 0) {
|
|
945
|
-
return Long.
|
|
932
|
+
return Long._fromString(str.substring(1), unsigned, radix).neg();
|
|
946
933
|
}
|
|
947
934
|
const radixToPower = Long.fromNumber(Math.pow(radix, 8));
|
|
948
935
|
let result = Long.ZERO;
|
|
@@ -960,6 +947,45 @@ class Long extends BSONValue {
|
|
|
960
947
|
result.unsigned = unsigned;
|
|
961
948
|
return result;
|
|
962
949
|
}
|
|
950
|
+
static fromStringStrict(str, unsignedOrRadix, radix) {
|
|
951
|
+
let unsigned = false;
|
|
952
|
+
if (typeof unsignedOrRadix === 'number') {
|
|
953
|
+
(radix = unsignedOrRadix), (unsignedOrRadix = false);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
unsigned = !!unsignedOrRadix;
|
|
957
|
+
}
|
|
958
|
+
radix ??= 10;
|
|
959
|
+
if (str.trim() !== str) {
|
|
960
|
+
throw new BSONError(`Input: '${str}' contains leading and/or trailing whitespace`);
|
|
961
|
+
}
|
|
962
|
+
if (!validateStringCharacters(str, radix)) {
|
|
963
|
+
throw new BSONError(`Input: '${str}' contains invalid characters for radix: ${radix}`);
|
|
964
|
+
}
|
|
965
|
+
const cleanedStr = removeLeadingZerosAndExplicitPlus(str);
|
|
966
|
+
const result = Long._fromString(cleanedStr, unsigned, radix);
|
|
967
|
+
if (result.toString(radix).toLowerCase() !== cleanedStr.toLowerCase()) {
|
|
968
|
+
throw new BSONError(`Input: ${str} is not representable as ${result.unsigned ? 'an unsigned' : 'a signed'} 64-bit Long ${radix != null ? `with radix: ${radix}` : ''}`);
|
|
969
|
+
}
|
|
970
|
+
return result;
|
|
971
|
+
}
|
|
972
|
+
static fromString(str, unsignedOrRadix, radix) {
|
|
973
|
+
let unsigned = false;
|
|
974
|
+
if (typeof unsignedOrRadix === 'number') {
|
|
975
|
+
(radix = unsignedOrRadix), (unsignedOrRadix = false);
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
unsigned = !!unsignedOrRadix;
|
|
979
|
+
}
|
|
980
|
+
radix ??= 10;
|
|
981
|
+
if (str === 'NaN' && radix < 24) {
|
|
982
|
+
return Long.ZERO;
|
|
983
|
+
}
|
|
984
|
+
else if ((str === 'Infinity' || str === '+Infinity' || str === '-Infinity') && radix < 35) {
|
|
985
|
+
return Long.ZERO;
|
|
986
|
+
}
|
|
987
|
+
return Long._fromString(str, unsigned, radix);
|
|
988
|
+
}
|
|
963
989
|
static fromBytes(bytes, unsigned, le) {
|
|
964
990
|
return le ? Long.fromBytesLE(bytes, unsigned) : Long.fromBytesBE(bytes, unsigned);
|
|
965
991
|
}
|
|
@@ -2037,6 +2063,28 @@ class Double extends BSONValue {
|
|
|
2037
2063
|
}
|
|
2038
2064
|
this.value = +value;
|
|
2039
2065
|
}
|
|
2066
|
+
static fromString(value) {
|
|
2067
|
+
const coercedValue = Number(value);
|
|
2068
|
+
if (value === 'NaN')
|
|
2069
|
+
return new Double(NaN);
|
|
2070
|
+
if (value === 'Infinity')
|
|
2071
|
+
return new Double(Infinity);
|
|
2072
|
+
if (value === '-Infinity')
|
|
2073
|
+
return new Double(-Infinity);
|
|
2074
|
+
if (!Number.isFinite(coercedValue)) {
|
|
2075
|
+
throw new BSONError(`Input: ${value} is not representable as a Double`);
|
|
2076
|
+
}
|
|
2077
|
+
if (value.trim() !== value) {
|
|
2078
|
+
throw new BSONError(`Input: '${value}' contains whitespace`);
|
|
2079
|
+
}
|
|
2080
|
+
if (value === '') {
|
|
2081
|
+
throw new BSONError(`Input is an empty string`);
|
|
2082
|
+
}
|
|
2083
|
+
if (/[^-0-9.+eE]/.test(value)) {
|
|
2084
|
+
throw new BSONError(`Input: '${value}' is not in decimal or exponential notation`);
|
|
2085
|
+
}
|
|
2086
|
+
return new Double(coercedValue);
|
|
2087
|
+
}
|
|
2040
2088
|
valueOf() {
|
|
2041
2089
|
return this.value;
|
|
2042
2090
|
}
|
|
@@ -2078,6 +2126,23 @@ class Int32 extends BSONValue {
|
|
|
2078
2126
|
}
|
|
2079
2127
|
this.value = +value | 0;
|
|
2080
2128
|
}
|
|
2129
|
+
static fromString(value) {
|
|
2130
|
+
const cleanedValue = removeLeadingZerosAndExplicitPlus(value);
|
|
2131
|
+
const coercedValue = Number(value);
|
|
2132
|
+
if (BSON_INT32_MAX < coercedValue) {
|
|
2133
|
+
throw new BSONError(`Input: '${value}' is larger than the maximum value for Int32`);
|
|
2134
|
+
}
|
|
2135
|
+
else if (BSON_INT32_MIN > coercedValue) {
|
|
2136
|
+
throw new BSONError(`Input: '${value}' is smaller than the minimum value for Int32`);
|
|
2137
|
+
}
|
|
2138
|
+
else if (!Number.isSafeInteger(coercedValue)) {
|
|
2139
|
+
throw new BSONError(`Input: '${value}' is not a safe integer`);
|
|
2140
|
+
}
|
|
2141
|
+
else if (coercedValue.toString() !== cleanedValue) {
|
|
2142
|
+
throw new BSONError(`Input: '${value}' is not a valid Int32 string`);
|
|
2143
|
+
}
|
|
2144
|
+
return new Int32(coercedValue);
|
|
2145
|
+
}
|
|
2081
2146
|
valueOf() {
|
|
2082
2147
|
return this.value;
|
|
2083
2148
|
}
|
|
@@ -3165,12 +3230,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
3165
3230
|
stringSize > buffer.length - index ||
|
|
3166
3231
|
buffer[index + stringSize - 1] !== 0)
|
|
3167
3232
|
throw new BSONError('bad string length in bson');
|
|
3168
|
-
|
|
3169
|
-
if (!validateUtf8(buffer, index, index + stringSize - 1)) {
|
|
3170
|
-
throw new BSONError('Invalid UTF-8 string in BSON document');
|
|
3171
|
-
}
|
|
3172
|
-
}
|
|
3173
|
-
const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, false);
|
|
3233
|
+
const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
|
|
3174
3234
|
index = index + stringSize;
|
|
3175
3235
|
const oidBuffer = ByteUtils.allocateUnsafe(12);
|
|
3176
3236
|
for (let i = 0; i < 12; i++)
|