bson 6.4.1 → 6.5.1
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 +50 -0
- package/lib/bson.bundle.js +110 -0
- package/lib/bson.bundle.js.map +1 -1
- package/lib/bson.cjs +110 -0
- package/lib/bson.cjs.map +1 -1
- package/lib/bson.mjs +110 -1
- package/lib/bson.mjs.map +1 -1
- package/lib/bson.rn.cjs +111 -0
- package/lib/bson.rn.cjs.map +1 -1
- package/package.json +1 -1
- package/src/binary.ts +2 -0
- package/src/bson.ts +1 -0
- package/src/constants.ts +3 -0
- package/src/error.ts +22 -0
- package/src/parser/on_demand/index.ts +28 -0
- package/src/parser/on_demand/parse_to_elements.ts +174 -0
package/package.json
CHANGED
package/src/binary.ts
CHANGED
|
@@ -56,6 +56,8 @@ export class Binary extends BSONValue {
|
|
|
56
56
|
static readonly SUBTYPE_ENCRYPTED = 6;
|
|
57
57
|
/** Column BSON type */
|
|
58
58
|
static readonly SUBTYPE_COLUMN = 7;
|
|
59
|
+
/** Sensitive BSON type */
|
|
60
|
+
static readonly SUBTYPE_SENSITIVE = 8;
|
|
59
61
|
/** User BSON type */
|
|
60
62
|
static readonly SUBTYPE_USER_DEFINED = 128;
|
|
61
63
|
|
package/src/bson.ts
CHANGED
|
@@ -54,6 +54,7 @@ export { BSONValue } from './bson_value';
|
|
|
54
54
|
export { BSONError, BSONVersionError, BSONRuntimeError } from './error';
|
|
55
55
|
export { BSONType } from './constants';
|
|
56
56
|
export { EJSON } from './extended_json';
|
|
57
|
+
export { onDemand } from './parser/on_demand/index';
|
|
57
58
|
|
|
58
59
|
/** @public */
|
|
59
60
|
export interface Document {
|
package/src/constants.ts
CHANGED
|
@@ -109,6 +109,9 @@ export const BSON_BINARY_SUBTYPE_ENCRYPTED = 6;
|
|
|
109
109
|
/** Column BSON type @internal */
|
|
110
110
|
export const BSON_BINARY_SUBTYPE_COLUMN = 7;
|
|
111
111
|
|
|
112
|
+
/** Sensitive BSON type @internal */
|
|
113
|
+
export const BSON_BINARY_SUBTYPE_SENSITIVE = 8;
|
|
114
|
+
|
|
112
115
|
/** Binary User Defined Type @internal */
|
|
113
116
|
export const BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
|
|
114
117
|
|
package/src/error.ts
CHANGED
|
@@ -81,3 +81,25 @@ export class BSONRuntimeError extends BSONError {
|
|
|
81
81
|
super(message);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @public
|
|
87
|
+
* @category Error
|
|
88
|
+
*
|
|
89
|
+
* @experimental
|
|
90
|
+
*
|
|
91
|
+
* An error generated when BSON bytes are invalid.
|
|
92
|
+
* Reports the offset the parser was able to reach before encountering the error.
|
|
93
|
+
*/
|
|
94
|
+
export class BSONOffsetError extends BSONError {
|
|
95
|
+
public get name(): 'BSONOffsetError' {
|
|
96
|
+
return 'BSONOffsetError';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public offset: number;
|
|
100
|
+
|
|
101
|
+
constructor(message: string, offset: number) {
|
|
102
|
+
super(`${message}. offset: ${offset}`);
|
|
103
|
+
this.offset = offset;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type BSONError, BSONOffsetError } from '../../error';
|
|
2
|
+
import { type BSONElement, parseToElements } from './parse_to_elements';
|
|
3
|
+
/**
|
|
4
|
+
* @experimental
|
|
5
|
+
* @public
|
|
6
|
+
*
|
|
7
|
+
* A new set of BSON APIs that are currently experimental and not intended for production use.
|
|
8
|
+
*/
|
|
9
|
+
export type OnDemand = {
|
|
10
|
+
BSONOffsetError: {
|
|
11
|
+
new (message: string, offset: number): BSONOffsetError;
|
|
12
|
+
isBSONError(value: unknown): value is BSONError;
|
|
13
|
+
};
|
|
14
|
+
parseToElements: (this: void, bytes: Uint8Array, startOffset?: number) => Iterable<BSONElement>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @experimental
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
const onDemand: OnDemand = Object.create(null);
|
|
22
|
+
|
|
23
|
+
onDemand.parseToElements = parseToElements;
|
|
24
|
+
onDemand.BSONOffsetError = BSONOffsetError;
|
|
25
|
+
|
|
26
|
+
Object.freeze(onDemand);
|
|
27
|
+
|
|
28
|
+
export { onDemand };
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
|
|
2
|
+
import { BSONOffsetError } from '../../error';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @internal
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* - This enum is const so the code we produce will inline the numbers
|
|
9
|
+
* - `minKey` is set to 255 so unsigned comparisons succeed
|
|
10
|
+
* - Modify with caution, double check the bundle contains literals
|
|
11
|
+
*/
|
|
12
|
+
const enum t {
|
|
13
|
+
double = 1,
|
|
14
|
+
string = 2,
|
|
15
|
+
object = 3,
|
|
16
|
+
array = 4,
|
|
17
|
+
binData = 5,
|
|
18
|
+
undefined = 6,
|
|
19
|
+
objectId = 7,
|
|
20
|
+
bool = 8,
|
|
21
|
+
date = 9,
|
|
22
|
+
null = 10,
|
|
23
|
+
regex = 11,
|
|
24
|
+
dbPointer = 12,
|
|
25
|
+
javascript = 13,
|
|
26
|
+
symbol = 14,
|
|
27
|
+
javascriptWithScope = 15,
|
|
28
|
+
int = 16,
|
|
29
|
+
timestamp = 17,
|
|
30
|
+
long = 18,
|
|
31
|
+
decimal = 19,
|
|
32
|
+
minKey = 255,
|
|
33
|
+
maxKey = 127
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @public
|
|
38
|
+
* @experimental
|
|
39
|
+
*/
|
|
40
|
+
export type BSONElement = [
|
|
41
|
+
type: number,
|
|
42
|
+
nameOffset: number,
|
|
43
|
+
nameLength: number,
|
|
44
|
+
offset: number,
|
|
45
|
+
length: number
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
/** Parses a int32 little-endian at offset, throws if it is negative */
|
|
49
|
+
function getSize(source: Uint8Array, offset: number): number {
|
|
50
|
+
if (source[offset + 3] > 127) {
|
|
51
|
+
throw new BSONOffsetError('BSON size cannot be negative', offset);
|
|
52
|
+
}
|
|
53
|
+
return (
|
|
54
|
+
source[offset] |
|
|
55
|
+
(source[offset + 1] << 8) |
|
|
56
|
+
(source[offset + 2] << 16) |
|
|
57
|
+
(source[offset + 3] << 24)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Searches for null terminator of a BSON element's value (Never the document null terminator)
|
|
63
|
+
* **Does not** bounds check since this should **ONLY** be used within parseToElements which has asserted that `bytes` ends with a `0x00`.
|
|
64
|
+
* So this will at most iterate to the document's terminator and error if that is the offset reached.
|
|
65
|
+
*/
|
|
66
|
+
function findNull(bytes: Uint8Array, offset: number): number {
|
|
67
|
+
let nullTerminatorOffset = offset;
|
|
68
|
+
|
|
69
|
+
for (; bytes[nullTerminatorOffset] !== 0x00; nullTerminatorOffset++);
|
|
70
|
+
|
|
71
|
+
if (nullTerminatorOffset === bytes.length - 1) {
|
|
72
|
+
// We reached the null terminator of the document, not a value's
|
|
73
|
+
throw new BSONOffsetError('Null terminator not found', offset);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return nullTerminatorOffset;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @public
|
|
81
|
+
* @experimental
|
|
82
|
+
*/
|
|
83
|
+
export function parseToElements(bytes: Uint8Array, startOffset = 0): Iterable<BSONElement> {
|
|
84
|
+
if (bytes.length < 5) {
|
|
85
|
+
throw new BSONOffsetError(
|
|
86
|
+
`Input must be at least 5 bytes, got ${bytes.length} bytes`,
|
|
87
|
+
startOffset
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const documentSize = getSize(bytes, startOffset);
|
|
92
|
+
|
|
93
|
+
if (documentSize > bytes.length - startOffset) {
|
|
94
|
+
throw new BSONOffsetError(
|
|
95
|
+
`Parsed documentSize (${documentSize} bytes) does not match input length (${bytes.length} bytes)`,
|
|
96
|
+
startOffset
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (bytes[startOffset + documentSize - 1] !== 0x00) {
|
|
101
|
+
throw new BSONOffsetError('BSON documents must end in 0x00', startOffset + documentSize);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const elements: BSONElement[] = [];
|
|
105
|
+
let offset = startOffset + 4;
|
|
106
|
+
|
|
107
|
+
while (offset <= documentSize + startOffset) {
|
|
108
|
+
const type = bytes[offset];
|
|
109
|
+
offset += 1;
|
|
110
|
+
|
|
111
|
+
if (type === 0) {
|
|
112
|
+
if (offset - startOffset !== documentSize) {
|
|
113
|
+
throw new BSONOffsetError(`Invalid 0x00 type byte`, offset);
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const nameOffset = offset;
|
|
119
|
+
const nameLength = findNull(bytes, offset) - nameOffset;
|
|
120
|
+
offset += nameLength + 1;
|
|
121
|
+
|
|
122
|
+
let length: number;
|
|
123
|
+
|
|
124
|
+
if (type === t.double || type === t.long || type === t.date || type === t.timestamp) {
|
|
125
|
+
length = 8;
|
|
126
|
+
} else if (type === t.int) {
|
|
127
|
+
length = 4;
|
|
128
|
+
} else if (type === t.objectId) {
|
|
129
|
+
length = 12;
|
|
130
|
+
} else if (type === t.decimal) {
|
|
131
|
+
length = 16;
|
|
132
|
+
} else if (type === t.bool) {
|
|
133
|
+
length = 1;
|
|
134
|
+
} else if (type === t.null || type === t.undefined || type === t.maxKey || type === t.minKey) {
|
|
135
|
+
length = 0;
|
|
136
|
+
}
|
|
137
|
+
// Needs a size calculation
|
|
138
|
+
else if (type === t.regex) {
|
|
139
|
+
length = findNull(bytes, findNull(bytes, offset) + 1) + 1 - offset;
|
|
140
|
+
} else if (type === t.object || type === t.array || type === t.javascriptWithScope) {
|
|
141
|
+
length = getSize(bytes, offset);
|
|
142
|
+
} else if (
|
|
143
|
+
type === t.string ||
|
|
144
|
+
type === t.binData ||
|
|
145
|
+
type === t.dbPointer ||
|
|
146
|
+
type === t.javascript ||
|
|
147
|
+
type === t.symbol
|
|
148
|
+
) {
|
|
149
|
+
length = getSize(bytes, offset) + 4;
|
|
150
|
+
if (type === t.binData) {
|
|
151
|
+
// binary subtype
|
|
152
|
+
length += 1;
|
|
153
|
+
}
|
|
154
|
+
if (type === t.dbPointer) {
|
|
155
|
+
// dbPointer's objectId
|
|
156
|
+
length += 12;
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
throw new BSONOffsetError(
|
|
160
|
+
`Invalid 0x${type.toString(16).padStart(2, '0')} type byte`,
|
|
161
|
+
offset
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (length > documentSize) {
|
|
166
|
+
throw new BSONOffsetError('value reports length larger than document', offset);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
elements.push([type, nameOffset, nameLength, offset, length]);
|
|
170
|
+
offset += length;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return elements;
|
|
174
|
+
}
|