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.cjs
CHANGED
|
@@ -97,8 +97,8 @@ class BSONError extends Error {
|
|
|
97
97
|
get name() {
|
|
98
98
|
return 'BSONError';
|
|
99
99
|
}
|
|
100
|
-
constructor(message) {
|
|
101
|
-
super(message);
|
|
100
|
+
constructor(message, options) {
|
|
101
|
+
super(message, options);
|
|
102
102
|
}
|
|
103
103
|
static isBSONError(value) {
|
|
104
104
|
return (value != null &&
|
|
@@ -127,6 +127,79 @@ class BSONRuntimeError extends BSONError {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
const FIRST_BIT = 0x80;
|
|
131
|
+
const FIRST_TWO_BITS = 0xc0;
|
|
132
|
+
const FIRST_THREE_BITS = 0xe0;
|
|
133
|
+
const FIRST_FOUR_BITS = 0xf0;
|
|
134
|
+
const FIRST_FIVE_BITS = 0xf8;
|
|
135
|
+
const TWO_BIT_CHAR = 0xc0;
|
|
136
|
+
const THREE_BIT_CHAR = 0xe0;
|
|
137
|
+
const FOUR_BIT_CHAR = 0xf0;
|
|
138
|
+
const CONTINUING_CHAR = 0x80;
|
|
139
|
+
function validateUtf8(bytes, start, end) {
|
|
140
|
+
let continuation = 0;
|
|
141
|
+
for (let i = start; i < end; i += 1) {
|
|
142
|
+
const byte = bytes[i];
|
|
143
|
+
if (continuation) {
|
|
144
|
+
if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
continuation -= 1;
|
|
148
|
+
}
|
|
149
|
+
else if (byte & FIRST_BIT) {
|
|
150
|
+
if ((byte & FIRST_THREE_BITS) === TWO_BIT_CHAR) {
|
|
151
|
+
continuation = 1;
|
|
152
|
+
}
|
|
153
|
+
else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
|
|
154
|
+
continuation = 2;
|
|
155
|
+
}
|
|
156
|
+
else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
|
|
157
|
+
continuation = 3;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return !continuation;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function tryLatin(uint8array, start, end) {
|
|
168
|
+
if (uint8array.length === 0) {
|
|
169
|
+
return '';
|
|
170
|
+
}
|
|
171
|
+
const stringByteLength = end - start;
|
|
172
|
+
if (stringByteLength === 0) {
|
|
173
|
+
return '';
|
|
174
|
+
}
|
|
175
|
+
if (stringByteLength > 20) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
if (stringByteLength === 1 && uint8array[start] < 128) {
|
|
179
|
+
return String.fromCharCode(uint8array[start]);
|
|
180
|
+
}
|
|
181
|
+
if (stringByteLength === 2 && uint8array[start] < 128 && uint8array[start + 1] < 128) {
|
|
182
|
+
return String.fromCharCode(uint8array[start]) + String.fromCharCode(uint8array[start + 1]);
|
|
183
|
+
}
|
|
184
|
+
if (stringByteLength === 3 &&
|
|
185
|
+
uint8array[start] < 128 &&
|
|
186
|
+
uint8array[start + 1] < 128 &&
|
|
187
|
+
uint8array[start + 2] < 128) {
|
|
188
|
+
return (String.fromCharCode(uint8array[start]) +
|
|
189
|
+
String.fromCharCode(uint8array[start + 1]) +
|
|
190
|
+
String.fromCharCode(uint8array[start + 2]));
|
|
191
|
+
}
|
|
192
|
+
const latinBytes = [];
|
|
193
|
+
for (let i = start; i < end; i++) {
|
|
194
|
+
const byte = uint8array[i];
|
|
195
|
+
if (byte > 127) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
latinBytes.push(byte);
|
|
199
|
+
}
|
|
200
|
+
return String.fromCharCode(...latinBytes);
|
|
201
|
+
}
|
|
202
|
+
|
|
130
203
|
function nodejsMathRandomBytes(byteLength) {
|
|
131
204
|
return nodeJsByteUtils.fromNumberArray(Array.from({ length: byteLength }, () => Math.floor(Math.random() * 256)));
|
|
132
205
|
}
|
|
@@ -185,8 +258,23 @@ const nodeJsByteUtils = {
|
|
|
185
258
|
fromUTF8(text) {
|
|
186
259
|
return Buffer.from(text, 'utf8');
|
|
187
260
|
},
|
|
188
|
-
toUTF8(buffer, start, end) {
|
|
189
|
-
|
|
261
|
+
toUTF8(buffer, start, end, fatal) {
|
|
262
|
+
const basicLatin = end - start <= 20 ? tryLatin(buffer, start, end) : null;
|
|
263
|
+
if (basicLatin != null) {
|
|
264
|
+
return basicLatin;
|
|
265
|
+
}
|
|
266
|
+
const string = nodeJsByteUtils.toLocalBufferType(buffer).toString('utf8', start, end);
|
|
267
|
+
if (fatal) {
|
|
268
|
+
for (let i = 0; i < string.length; i++) {
|
|
269
|
+
if (string.charCodeAt(i) === 0xfffd) {
|
|
270
|
+
if (!validateUtf8(buffer, start, end)) {
|
|
271
|
+
throw new BSONError('Invalid UTF-8 string in BSON document');
|
|
272
|
+
}
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return string;
|
|
190
278
|
},
|
|
191
279
|
utf8ByteLength(input) {
|
|
192
280
|
return Buffer.byteLength(input, 'utf8');
|
|
@@ -296,8 +384,20 @@ const webByteUtils = {
|
|
|
296
384
|
fromUTF8(text) {
|
|
297
385
|
return new TextEncoder().encode(text);
|
|
298
386
|
},
|
|
299
|
-
toUTF8(uint8array, start, end) {
|
|
300
|
-
|
|
387
|
+
toUTF8(uint8array, start, end, fatal) {
|
|
388
|
+
const basicLatin = end - start <= 20 ? tryLatin(uint8array, start, end) : null;
|
|
389
|
+
if (basicLatin != null) {
|
|
390
|
+
return basicLatin;
|
|
391
|
+
}
|
|
392
|
+
if (fatal) {
|
|
393
|
+
try {
|
|
394
|
+
return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
|
|
395
|
+
}
|
|
396
|
+
catch (cause) {
|
|
397
|
+
throw new BSONError('Invalid UTF-8 string in BSON document', { cause });
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
|
|
301
401
|
},
|
|
302
402
|
utf8ByteLength(input) {
|
|
303
403
|
return webByteUtils.fromUTF8(input).byteLength;
|
|
@@ -418,8 +518,8 @@ class Binary extends BSONValue {
|
|
|
418
518
|
if (encoding === 'base64')
|
|
419
519
|
return ByteUtils.toBase64(this.buffer);
|
|
420
520
|
if (encoding === 'utf8' || encoding === 'utf-8')
|
|
421
|
-
return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
|
|
422
|
-
return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
|
|
521
|
+
return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength, false);
|
|
522
|
+
return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength, false);
|
|
423
523
|
}
|
|
424
524
|
toExtendedJSON(options) {
|
|
425
525
|
options = options || {};
|
|
@@ -2507,43 +2607,6 @@ class Timestamp extends LongWithoutOverridesClass {
|
|
|
2507
2607
|
}
|
|
2508
2608
|
Timestamp.MAX_VALUE = Long.MAX_UNSIGNED_VALUE;
|
|
2509
2609
|
|
|
2510
|
-
const FIRST_BIT = 0x80;
|
|
2511
|
-
const FIRST_TWO_BITS = 0xc0;
|
|
2512
|
-
const FIRST_THREE_BITS = 0xe0;
|
|
2513
|
-
const FIRST_FOUR_BITS = 0xf0;
|
|
2514
|
-
const FIRST_FIVE_BITS = 0xf8;
|
|
2515
|
-
const TWO_BIT_CHAR = 0xc0;
|
|
2516
|
-
const THREE_BIT_CHAR = 0xe0;
|
|
2517
|
-
const FOUR_BIT_CHAR = 0xf0;
|
|
2518
|
-
const CONTINUING_CHAR = 0x80;
|
|
2519
|
-
function validateUtf8(bytes, start, end) {
|
|
2520
|
-
let continuation = 0;
|
|
2521
|
-
for (let i = start; i < end; i += 1) {
|
|
2522
|
-
const byte = bytes[i];
|
|
2523
|
-
if (continuation) {
|
|
2524
|
-
if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
|
|
2525
|
-
return false;
|
|
2526
|
-
}
|
|
2527
|
-
continuation -= 1;
|
|
2528
|
-
}
|
|
2529
|
-
else if (byte & FIRST_BIT) {
|
|
2530
|
-
if ((byte & FIRST_THREE_BITS) === TWO_BIT_CHAR) {
|
|
2531
|
-
continuation = 1;
|
|
2532
|
-
}
|
|
2533
|
-
else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
|
|
2534
|
-
continuation = 2;
|
|
2535
|
-
}
|
|
2536
|
-
else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
|
|
2537
|
-
continuation = 3;
|
|
2538
|
-
}
|
|
2539
|
-
else {
|
|
2540
|
-
return false;
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
}
|
|
2544
|
-
return !continuation;
|
|
2545
|
-
}
|
|
2546
|
-
|
|
2547
2610
|
const JS_INT_MAX_LONG = Long.fromNumber(JS_INT_MAX);
|
|
2548
2611
|
const JS_INT_MIN_LONG = Long.fromNumber(JS_INT_MIN);
|
|
2549
2612
|
function internalDeserialize(buffer, options, isArray) {
|
|
@@ -2635,7 +2698,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2635
2698
|
}
|
|
2636
2699
|
if (i >= buffer.byteLength)
|
|
2637
2700
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2638
|
-
const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i);
|
|
2701
|
+
const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i, false);
|
|
2639
2702
|
let shouldValidateKey = true;
|
|
2640
2703
|
if (globalUTFValidation || utf8KeysSet.has(name)) {
|
|
2641
2704
|
shouldValidateKey = validationSetting;
|
|
@@ -2658,7 +2721,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2658
2721
|
buffer[index + stringSize - 1] !== 0) {
|
|
2659
2722
|
throw new BSONError('bad string length in bson');
|
|
2660
2723
|
}
|
|
2661
|
-
value =
|
|
2724
|
+
value = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
|
|
2662
2725
|
index = index + stringSize;
|
|
2663
2726
|
}
|
|
2664
2727
|
else if (elementType === BSON_DATA_OID) {
|
|
@@ -2850,7 +2913,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2850
2913
|
}
|
|
2851
2914
|
if (i >= buffer.length)
|
|
2852
2915
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2853
|
-
const source = ByteUtils.toUTF8(buffer, index, i);
|
|
2916
|
+
const source = ByteUtils.toUTF8(buffer, index, i, false);
|
|
2854
2917
|
index = i + 1;
|
|
2855
2918
|
i = index;
|
|
2856
2919
|
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
@@ -2858,7 +2921,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2858
2921
|
}
|
|
2859
2922
|
if (i >= buffer.length)
|
|
2860
2923
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2861
|
-
const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
|
|
2924
|
+
const regExpOptions = ByteUtils.toUTF8(buffer, index, i, false);
|
|
2862
2925
|
index = i + 1;
|
|
2863
2926
|
const optionsArray = new Array(regExpOptions.length);
|
|
2864
2927
|
for (i = 0; i < regExpOptions.length; i++) {
|
|
@@ -2883,7 +2946,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2883
2946
|
}
|
|
2884
2947
|
if (i >= buffer.length)
|
|
2885
2948
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2886
|
-
const source = ByteUtils.toUTF8(buffer, index, i);
|
|
2949
|
+
const source = ByteUtils.toUTF8(buffer, index, i, false);
|
|
2887
2950
|
index = i + 1;
|
|
2888
2951
|
i = index;
|
|
2889
2952
|
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
@@ -2891,7 +2954,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2891
2954
|
}
|
|
2892
2955
|
if (i >= buffer.length)
|
|
2893
2956
|
throw new BSONError('Bad BSON Document: illegal CString');
|
|
2894
|
-
const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
|
|
2957
|
+
const regExpOptions = ByteUtils.toUTF8(buffer, index, i, false);
|
|
2895
2958
|
index = i + 1;
|
|
2896
2959
|
value = new BSONRegExp(source, regExpOptions);
|
|
2897
2960
|
}
|
|
@@ -2905,7 +2968,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2905
2968
|
buffer[index + stringSize - 1] !== 0) {
|
|
2906
2969
|
throw new BSONError('bad string length in bson');
|
|
2907
2970
|
}
|
|
2908
|
-
const symbol =
|
|
2971
|
+
const symbol = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
|
|
2909
2972
|
value = promoteValues ? symbol : new BSONSymbol(symbol);
|
|
2910
2973
|
index = index + stringSize;
|
|
2911
2974
|
}
|
|
@@ -2936,7 +2999,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2936
2999
|
buffer[index + stringSize - 1] !== 0) {
|
|
2937
3000
|
throw new BSONError('bad string length in bson');
|
|
2938
3001
|
}
|
|
2939
|
-
const functionString =
|
|
3002
|
+
const functionString = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
|
|
2940
3003
|
value = new Code(functionString);
|
|
2941
3004
|
index = index + stringSize;
|
|
2942
3005
|
}
|
|
@@ -2957,7 +3020,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2957
3020
|
buffer[index + stringSize - 1] !== 0) {
|
|
2958
3021
|
throw new BSONError('bad string length in bson');
|
|
2959
3022
|
}
|
|
2960
|
-
const functionString =
|
|
3023
|
+
const functionString = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
|
|
2961
3024
|
index = index + stringSize;
|
|
2962
3025
|
const _index = index;
|
|
2963
3026
|
const objectSize = buffer[index] |
|
|
@@ -2988,7 +3051,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
2988
3051
|
throw new BSONError('Invalid UTF-8 string in BSON document');
|
|
2989
3052
|
}
|
|
2990
3053
|
}
|
|
2991
|
-
const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1);
|
|
3054
|
+
const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, false);
|
|
2992
3055
|
index = index + stringSize;
|
|
2993
3056
|
const oidBuffer = ByteUtils.allocate(12);
|
|
2994
3057
|
oidBuffer.set(buffer.subarray(index, index + 12), 0);
|
|
@@ -3027,20 +3090,6 @@ function deserializeObject(buffer, index, options, isArray = false) {
|
|
|
3027
3090
|
}
|
|
3028
3091
|
return object;
|
|
3029
3092
|
}
|
|
3030
|
-
function getValidatedString(buffer, start, end, shouldValidateUtf8) {
|
|
3031
|
-
const value = ByteUtils.toUTF8(buffer, start, end);
|
|
3032
|
-
if (shouldValidateUtf8) {
|
|
3033
|
-
for (let i = 0; i < value.length; i++) {
|
|
3034
|
-
if (value.charCodeAt(i) === 0xfffd) {
|
|
3035
|
-
if (!validateUtf8(buffer, start, end)) {
|
|
3036
|
-
throw new BSONError('Invalid UTF-8 string in BSON document');
|
|
3037
|
-
}
|
|
3038
|
-
break;
|
|
3039
|
-
}
|
|
3040
|
-
}
|
|
3041
|
-
}
|
|
3042
|
-
return value;
|
|
3043
|
-
}
|
|
3044
3093
|
|
|
3045
3094
|
const regexp = /\x00/;
|
|
3046
3095
|
const ignoreKeys = new Set(['$db', '$ref', '$id', '$clusterTime']);
|