bson 6.2.0 → 6.3.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/bson.d.ts +39 -4
- package/lib/bson.bundle.js +118 -69
- package/lib/bson.bundle.js.map +1 -1
- package/lib/bson.cjs +118 -69
- package/lib/bson.cjs.map +1 -1
- package/lib/bson.mjs +118 -69
- package/lib/bson.mjs.map +1 -1
- package/lib/bson.rn.cjs +118 -69
- package/lib/bson.rn.cjs.map +1 -1
- package/package.json +19 -16
- package/src/binary.ts +2 -2
- package/src/error.ts +3 -3
- package/src/objectid.ts +42 -3
- package/src/parser/deserializer.ts +10 -31
- package/src/utils/byte_utils.ts +2 -2
- package/src/utils/latin.ts +61 -0
- package/src/utils/node_byte_utils.ts +21 -2
- package/src/utils/web_byte_utils.ts +15 -2
package/lib/bson.mjs
CHANGED
|
@@ -95,8 +95,8 @@ class BSONError extends Error {
|
|
|
95
95
|
get name() {
|
|
96
96
|
return 'BSONError';
|
|
97
97
|
}
|
|
98
|
-
constructor(message) {
|
|
99
|
-
super(message);
|
|
98
|
+
constructor(message, options) {
|
|
99
|
+
super(message, options);
|
|
100
100
|
}
|
|
101
101
|
static isBSONError(value) {
|
|
102
102
|
return (value != null &&
|
|
@@ -125,6 +125,79 @@ class BSONRuntimeError extends BSONError {
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
const FIRST_BIT = 0x80;
|
|
129
|
+
const FIRST_TWO_BITS = 0xc0;
|
|
130
|
+
const FIRST_THREE_BITS = 0xe0;
|
|
131
|
+
const FIRST_FOUR_BITS = 0xf0;
|
|
132
|
+
const FIRST_FIVE_BITS = 0xf8;
|
|
133
|
+
const TWO_BIT_CHAR = 0xc0;
|
|
134
|
+
const THREE_BIT_CHAR = 0xe0;
|
|
135
|
+
const FOUR_BIT_CHAR = 0xf0;
|
|
136
|
+
const CONTINUING_CHAR = 0x80;
|
|
137
|
+
function validateUtf8(bytes, start, end) {
|
|
138
|
+
let continuation = 0;
|
|
139
|
+
for (let i = start; i < end; i += 1) {
|
|
140
|
+
const byte = bytes[i];
|
|
141
|
+
if (continuation) {
|
|
142
|
+
if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
continuation -= 1;
|
|
146
|
+
}
|
|
147
|
+
else if (byte & FIRST_BIT) {
|
|
148
|
+
if ((byte & FIRST_THREE_BITS) === TWO_BIT_CHAR) {
|
|
149
|
+
continuation = 1;
|
|
150
|
+
}
|
|
151
|
+
else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
|
|
152
|
+
continuation = 2;
|
|
153
|
+
}
|
|
154
|
+
else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
|
|
155
|
+
continuation = 3;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return !continuation;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function tryLatin(uint8array, start, end) {
|
|
166
|
+
if (uint8array.length === 0) {
|
|
167
|
+
return '';
|
|
168
|
+
}
|
|
169
|
+
const stringByteLength = end - start;
|
|
170
|
+
if (stringByteLength === 0) {
|
|
171
|
+
return '';
|
|
172
|
+
}
|
|
173
|
+
if (stringByteLength > 20) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
if (stringByteLength === 1 && uint8array[start] < 128) {
|
|
177
|
+
return String.fromCharCode(uint8array[start]);
|
|
178
|
+
}
|
|
179
|
+
if (stringByteLength === 2 && uint8array[start] < 128 && uint8array[start + 1] < 128) {
|
|
180
|
+
return String.fromCharCode(uint8array[start]) + String.fromCharCode(uint8array[start + 1]);
|
|
181
|
+
}
|
|
182
|
+
if (stringByteLength === 3 &&
|
|
183
|
+
uint8array[start] < 128 &&
|
|
184
|
+
uint8array[start + 1] < 128 &&
|
|
185
|
+
uint8array[start + 2] < 128) {
|
|
186
|
+
return (String.fromCharCode(uint8array[start]) +
|
|
187
|
+
String.fromCharCode(uint8array[start + 1]) +
|
|
188
|
+
String.fromCharCode(uint8array[start + 2]));
|
|
189
|
+
}
|
|
190
|
+
const latinBytes = [];
|
|
191
|
+
for (let i = start; i < end; i++) {
|
|
192
|
+
const byte = uint8array[i];
|
|
193
|
+
if (byte > 127) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
latinBytes.push(byte);
|
|
197
|
+
}
|
|
198
|
+
return String.fromCharCode(...latinBytes);
|
|
199
|
+
}
|
|
200
|
+
|
|
128
201
|
function nodejsMathRandomBytes(byteLength) {
|
|
129
202
|
return nodeJsByteUtils.fromNumberArray(Array.from({ length: byteLength }, () => Math.floor(Math.random() * 256)));
|
|
130
203
|
}
|
|
@@ -183,8 +256,23 @@ const nodeJsByteUtils = {
|
|
|
183
256
|
fromUTF8(text) {
|
|
184
257
|
return Buffer.from(text, 'utf8');
|
|
185
258
|
},
|
|
186
|
-
toUTF8(buffer, start, end) {
|
|
187
|
-
|
|
259
|
+
toUTF8(buffer, start, end, fatal) {
|
|
260
|
+
const basicLatin = end - start <= 20 ? tryLatin(buffer, start, end) : null;
|
|
261
|
+
if (basicLatin != null) {
|
|
262
|
+
return basicLatin;
|
|
263
|
+
}
|
|
264
|
+
const string = nodeJsByteUtils.toLocalBufferType(buffer).toString('utf8', start, end);
|
|
265
|
+
if (fatal) {
|
|
266
|
+
for (let i = 0; i < string.length; i++) {
|
|
267
|
+
if (string.charCodeAt(i) === 0xfffd) {
|
|
268
|
+
if (!validateUtf8(buffer, start, end)) {
|
|
269
|
+
throw new BSONError('Invalid UTF-8 string in BSON document');
|
|
270
|
+
}
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return string;
|
|
188
276
|
},
|
|
189
277
|
utf8ByteLength(input) {
|
|
190
278
|
return Buffer.byteLength(input, 'utf8');
|
|
@@ -294,8 +382,20 @@ const webByteUtils = {
|
|
|
294
382
|
fromUTF8(text) {
|
|
295
383
|
return new TextEncoder().encode(text);
|
|
296
384
|
},
|
|
297
|
-
toUTF8(uint8array, start, end) {
|
|
298
|
-
|
|
385
|
+
toUTF8(uint8array, start, end, fatal) {
|
|
386
|
+
const basicLatin = end - start <= 20 ? tryLatin(uint8array, start, end) : null;
|
|
387
|
+
if (basicLatin != null) {
|
|
388
|
+
return basicLatin;
|
|
389
|
+
}
|
|
390
|
+
if (fatal) {
|
|
391
|
+
try {
|
|
392
|
+
return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
|
|
393
|
+
}
|
|
394
|
+
catch (cause) {
|
|
395
|
+
throw new BSONError('Invalid UTF-8 string in BSON document', { cause });
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
|
|
299
399
|
},
|
|
300
400
|
utf8ByteLength(input) {
|
|
301
401
|
return webByteUtils.fromUTF8(input).byteLength;
|
|
@@ -416,8 +516,8 @@ class Binary extends BSONValue {
|
|
|
416
516
|
if (encoding === 'base64')
|
|
417
517
|
return ByteUtils.toBase64(this.buffer);
|
|
418
518
|
if (encoding === 'utf8' || encoding === 'utf-8')
|
|
419
|
-
return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
|
|
420
|
-
return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
|
|
519
|
+
return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength, false);
|
|
520
|
+
return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength, false);
|
|
421
521
|
}
|
|
422
522
|
toExtendedJSON(options) {
|
|
423
523
|
options = options || {};
|
|
@@ -2505,43 +2605,6 @@ class Timestamp extends LongWithoutOverridesClass {
|
|
|
2505
2605
|
}
|
|
2506
2606
|
Timestamp.MAX_VALUE = Long.MAX_UNSIGNED_VALUE;
|
|
2507
2607
|
|
|
2508
|
-
const FIRST_BIT = 0x80;
|
|
2509
|
-
const FIRST_TWO_BITS = 0xc0;
|
|
2510
|
-
const FIRST_THREE_BITS = 0xe0;
|
|
2511
|
-
const FIRST_FOUR_BITS = 0xf0;
|
|
2512
|
-
const FIRST_FIVE_BITS = 0xf8;
|
|
2513
|
-
const TWO_BIT_CHAR = 0xc0;
|
|
2514
|
-
const THREE_BIT_CHAR = 0xe0;
|
|
2515
|
-
const FOUR_BIT_CHAR = 0xf0;
|
|
2516
|
-
const CONTINUING_CHAR = 0x80;
|
|
2517
|
-
function validateUtf8(bytes, start, end) {
|
|
2518
|
-
let continuation = 0;
|
|
2519
|
-
for (let i = start; i < end; i += 1) {
|
|
2520
|
-
const byte = bytes[i];
|
|
2521
|
-
if (continuation) {
|
|
2522
|
-
if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
|
|
2523
|
-
return false;
|
|
2524
|
-
}
|
|
2525
|
-
continuation -= 1;
|
|
2526
|
-
}
|
|
2527
|
-
else if (byte & FIRST_BIT) {
|
|
2528
|
-
if ((byte & FIRST_THREE_BITS) === TWO_BIT_CHAR) {
|
|
2529
|
-
continuation = 1;
|
|
2530
|
-
}
|
|
2531
|
-
else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
|
|
2532
|
-
continuation = 2;
|
|
2533
|
-
}
|
|
2534
|
-
else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
|
|
2535
|
-
continuation = 3;
|
|
2536
|
-
}
|
|
2537
|
-
else {
|
|
2538
|
-
return false;
|
|
2539
|
-
}
|
|
2540
|
-
}
|
|
2541
|
-
}
|
|
2542
|
-
return !continuation;
|
|
2543
|
-
}
|
|
2544
|
-
|
|
2545
2608
|
const JS_INT_MAX_LONG = Long.fromNumber(JS_INT_MAX);
|
|
2546
2609
|
const JS_INT_MIN_LONG = Long.fromNumber(JS_INT_MIN);
|
|
2547
2610
|
function internalDeserialize(buffer, options, isArray) {
|
|
@@ -2633,7 +2696,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2633
2696
|
}
|
|
2634
2697
|
if (i >= buffer.byteLength)
|
|
2635
2698
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2636
|
-
const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i);
|
|
2699
|
+
const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i, false);
|
|
2637
2700
|
let shouldValidateKey = true;
|
|
2638
2701
|
if (globalUTFValidation || utf8KeysSet.has(name)) {
|
|
2639
2702
|
shouldValidateKey = validationSetting;
|
|
@@ -2656,7 +2719,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2656
2719
|
buffer[index + stringSize - 1] !== 0) {
|
|
2657
2720
|
throw new BSONError('bad string length in bson');
|
|
2658
2721
|
}
|
|
2659
|
-
value =
|
|
2722
|
+
value = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
|
|
2660
2723
|
index = index + stringSize;
|
|
2661
2724
|
}
|
|
2662
2725
|
else if (elementType === BSON_DATA_OID) {
|
|
@@ -2848,7 +2911,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2848
2911
|
}
|
|
2849
2912
|
if (i >= buffer.length)
|
|
2850
2913
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2851
|
-
const source = ByteUtils.toUTF8(buffer, index, i);
|
|
2914
|
+
const source = ByteUtils.toUTF8(buffer, index, i, false);
|
|
2852
2915
|
index = i + 1;
|
|
2853
2916
|
i = index;
|
|
2854
2917
|
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
@@ -2856,7 +2919,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2856
2919
|
}
|
|
2857
2920
|
if (i >= buffer.length)
|
|
2858
2921
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2859
|
-
const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
|
|
2922
|
+
const regExpOptions = ByteUtils.toUTF8(buffer, index, i, false);
|
|
2860
2923
|
index = i + 1;
|
|
2861
2924
|
const optionsArray = new Array(regExpOptions.length);
|
|
2862
2925
|
for (i = 0; i < regExpOptions.length; i++) {
|
|
@@ -2881,7 +2944,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2881
2944
|
}
|
|
2882
2945
|
if (i >= buffer.length)
|
|
2883
2946
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2884
|
-
const source = ByteUtils.toUTF8(buffer, index, i);
|
|
2947
|
+
const source = ByteUtils.toUTF8(buffer, index, i, false);
|
|
2885
2948
|
index = i + 1;
|
|
2886
2949
|
i = index;
|
|
2887
2950
|
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
@@ -2889,7 +2952,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2889
2952
|
}
|
|
2890
2953
|
if (i >= buffer.length)
|
|
2891
2954
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2892
|
-
const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
|
|
2955
|
+
const regExpOptions = ByteUtils.toUTF8(buffer, index, i, false);
|
|
2893
2956
|
index = i + 1;
|
|
2894
2957
|
value = new BSONRegExp(source, regExpOptions);
|
|
2895
2958
|
}
|
|
@@ -2903,7 +2966,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2903
2966
|
buffer[index + stringSize - 1] !== 0) {
|
|
2904
2967
|
throw new BSONError('bad string length in bson');
|
|
2905
2968
|
}
|
|
2906
|
-
const symbol =
|
|
2969
|
+
const symbol = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
|
|
2907
2970
|
value = promoteValues ? symbol : new BSONSymbol(symbol);
|
|
2908
2971
|
index = index + stringSize;
|
|
2909
2972
|
}
|
|
@@ -2934,7 +2997,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2934
2997
|
buffer[index + stringSize - 1] !== 0) {
|
|
2935
2998
|
throw new BSONError('bad string length in bson');
|
|
2936
2999
|
}
|
|
2937
|
-
const functionString =
|
|
3000
|
+
const functionString = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
|
|
2938
3001
|
value = new Code(functionString);
|
|
2939
3002
|
index = index + stringSize;
|
|
2940
3003
|
}
|
|
@@ -2955,7 +3018,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2955
3018
|
buffer[index + stringSize - 1] !== 0) {
|
|
2956
3019
|
throw new BSONError('bad string length in bson');
|
|
2957
3020
|
}
|
|
2958
|
-
const functionString =
|
|
3021
|
+
const functionString = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
|
|
2959
3022
|
index = index + stringSize;
|
|
2960
3023
|
const _index = index;
|
|
2961
3024
|
const objectSize = buffer[index] |
|
|
@@ -2986,7 +3049,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2986
3049
|
throw new BSONError('Invalid UTF-8 string in BSON document');
|
|
2987
3050
|
}
|
|
2988
3051
|
}
|
|
2989
|
-
const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1);
|
|
3052
|
+
const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, false);
|
|
2990
3053
|
index = index + stringSize;
|
|
2991
3054
|
const oidBuffer = ByteUtils.allocate(12);
|
|
2992
3055
|
oidBuffer.set(buffer.subarray(index, index + 12), 0);
|
|
@@ -3025,20 +3088,6 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
3025
3088
|
}
|
|
3026
3089
|
return object;
|
|
3027
3090
|
}
|
|
3028
|
-
function getValidatedString(buffer, start, end, shouldValidateUtf8) {
|
|
3029
|
-
const value = ByteUtils.toUTF8(buffer, start, end);
|
|
3030
|
-
if (shouldValidateUtf8) {
|
|
3031
|
-
for (let i = 0; i < value.length; i++) {
|
|
3032
|
-
if (value.charCodeAt(i) === 0xfffd) {
|
|
3033
|
-
if (!validateUtf8(buffer, start, end)) {
|
|
3034
|
-
throw new BSONError('Invalid UTF-8 string in BSON document');
|
|
3035
|
-
}
|
|
3036
|
-
break;
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
|
-
}
|
|
3040
|
-
return value;
|
|
3041
|
-
}
|
|
3042
3091
|
|
|
3043
3092
|
const regexp = /\x00/;
|
|
3044
3093
|
const ignoreKeys = new Set(['$db', '$ref', '$id', '$clusterTime']);
|