import { Buffer } from 'buffer'; import { Binary, UUID } from './binary'; import { Code } from './code'; import { DBRef } from './db_ref'; import { Decimal128 } from './decimal128'; import { Double } from './double'; import { ensureBuffer } from './ensure_buffer'; import { EJSON } from './extended_json'; import { Int32 } from './int_32'; import { Long } from './long'; import { Map } from './map'; import { MaxKey } from './max_key'; import { MinKey } from './min_key'; import { ObjectId } from './objectid'; import { BSONError, BSONTypeError } from './error'; import { calculateObjectSize as internalCalculateObjectSize } from './parser/calculate_size'; // Parts of the parser import { deserialize as internalDeserialize, DeserializeOptions } from './parser/deserializer'; import { serializeInto as internalSerialize, SerializeOptions } from './parser/serializer'; import { BSONRegExp } from './regexp'; import { BSONSymbol } from './symbol'; import { Timestamp } from './timestamp'; export type { UUIDExtended, BinaryExtended, BinaryExtendedLegacy, BinarySequence } from './binary'; export type { CodeExtended } from './code'; export { BSON_BINARY_SUBTYPE_BYTE_ARRAY, BSON_BINARY_SUBTYPE_DEFAULT, BSON_BINARY_SUBTYPE_FUNCTION, BSON_BINARY_SUBTYPE_MD5, BSON_BINARY_SUBTYPE_USER_DEFINED, BSON_BINARY_SUBTYPE_UUID, BSON_BINARY_SUBTYPE_UUID_NEW, BSON_BINARY_SUBTYPE_ENCRYPTED, BSON_BINARY_SUBTYPE_COLUMN, BSON_DATA_ARRAY, BSON_DATA_BINARY, BSON_DATA_BOOLEAN, BSON_DATA_CODE, BSON_DATA_CODE_W_SCOPE, BSON_DATA_DATE, BSON_DATA_DBPOINTER, BSON_DATA_DECIMAL128, BSON_DATA_INT, BSON_DATA_LONG, BSON_DATA_MAX_KEY, BSON_DATA_MIN_KEY, BSON_DATA_NULL, BSON_DATA_NUMBER, BSON_DATA_OBJECT, BSON_DATA_OID, BSON_DATA_REGEXP, BSON_DATA_STRING, BSON_DATA_SYMBOL, BSON_DATA_TIMESTAMP, BSON_DATA_UNDEFINED, BSON_INT32_MAX, BSON_INT32_MIN, BSON_INT64_MAX, BSON_INT64_MIN } from './constants'; export type { DBRefLike } from './db_ref'; export type { Decimal128Extended } from './decimal128'; export type { DoubleExtended } from './double'; export type { EJSONOptions } from './extended_json'; export { EJSON } from './extended_json'; export type { Int32Extended } from './int_32'; export type { LongExtended } from './long'; export type { MaxKeyExtended } from './max_key'; export type { MinKeyExtended } from './min_key'; export type { ObjectIdExtended, ObjectIdLike } from './objectid'; export type { BSONRegExpExtended, BSONRegExpExtendedLegacy } from './regexp'; export type { BSONSymbolExtended } from './symbol'; export type { LongWithoutOverrides, TimestampExtended, TimestampOverrides } from './timestamp'; export { LongWithoutOverridesClass } from './timestamp'; export type { SerializeOptions, DeserializeOptions }; export { Code, Map, BSONSymbol, DBRef, Binary, ObjectId, UUID, Long, Timestamp, Double, Int32, MinKey, MaxKey, BSONRegExp, Decimal128, // In 4.0.0 and 4.0.1, this property name was changed to ObjectId to match the class name. // This caused interoperability problems with previous versions of the library, so in // later builds we changed it back to ObjectID (capital D) to match legacy implementations. ObjectId as ObjectID }; export { BSONError, BSONTypeError } from './error'; /** @public */ export interface Document { // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; } /** @internal */ // Default Max Size const MAXSIZE = 1024 * 1024 * 17; // Current Internal Temporary Serialization Buffer let buffer = Buffer.alloc(MAXSIZE); /** * Sets the size of the internal serialization buffer. * * @param size - The desired size for the internal serialization buffer * @public */ export function setInternalBufferSize(size: number): void { // Resize the internal serialization buffer if needed if (buffer.length < size) { buffer = Buffer.alloc(size); } } /** * Serialize a Javascript object. * * @param object - the Javascript object to serialize. * @returns Buffer object containing the serialized object. * @public */ export function serialize(object: Document, options: SerializeOptions = {}): Buffer { // Unpack the options const checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false; const serializeFunctions = typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false; const ignoreUndefined = typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true; const minInternalBufferSize = typeof options.minInternalBufferSize === 'number' ? options.minInternalBufferSize : MAXSIZE; // Resize the internal serialization buffer if needed if (buffer.length < minInternalBufferSize) { buffer = Buffer.alloc(minInternalBufferSize); } // Attempt to serialize const serializationIndex = internalSerialize( buffer, object, checkKeys, 0, 0, serializeFunctions, ignoreUndefined, [] ); // Create the final buffer const finishedBuffer = Buffer.alloc(serializationIndex); // Copy into the finished buffer buffer.copy(finishedBuffer, 0, 0, finishedBuffer.length); // Return the buffer return finishedBuffer; } /** * Serialize a Javascript object using a predefined Buffer and index into the buffer, * useful when pre-allocating the space for serialization. * * @param object - the Javascript object to serialize. * @param finalBuffer - the Buffer you pre-allocated to store the serialized BSON object. * @returns the index pointing to the last written byte in the buffer. * @public */ export function serializeWithBufferAndIndex( object: Document, finalBuffer: Buffer, options: SerializeOptions = {} ): number { // Unpack the options const checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false; const serializeFunctions = typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false; const ignoreUndefined = typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true; const startIndex = typeof options.index === 'number' ? options.index : 0; // Attempt to serialize const serializationIndex = internalSerialize( buffer, object, checkKeys, 0, 0, serializeFunctions, ignoreUndefined ); buffer.copy(finalBuffer, startIndex, 0, serializationIndex); // Return the index return startIndex + serializationIndex - 1; } /** * Deserialize data as BSON. * * @param buffer - the buffer containing the serialized set of BSON documents. * @returns returns the deserialized Javascript Object. * @public */ export function deserialize( buffer: Buffer | ArrayBufferView | ArrayBuffer, options: DeserializeOptions = {} ): Document { return internalDeserialize(buffer instanceof Buffer ? buffer : ensureBuffer(buffer), options); } /** @public */ export type CalculateObjectSizeOptions = Pick< SerializeOptions, 'serializeFunctions' | 'ignoreUndefined' >; /** * Calculate the bson size for a passed in Javascript object. * * @param object - the Javascript object to calculate the BSON byte size for * @returns size of BSON object in bytes * @public */ export function calculateObjectSize( object: Document, options: CalculateObjectSizeOptions = {} ): number { options = options || {}; const serializeFunctions = typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false; const ignoreUndefined = typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true; return internalCalculateObjectSize(object, serializeFunctions, ignoreUndefined); } /** * Deserialize stream data as BSON documents. * * @param data - the buffer containing the serialized set of BSON documents. * @param startIndex - the start index in the data Buffer where the deserialization is to start. * @param numberOfDocuments - number of documents to deserialize. * @param documents - an array where to store the deserialized documents. * @param docStartIndex - the index in the documents array from where to start inserting documents. * @param options - additional options used for the deserialization. * @returns next index in the buffer after deserialization **x** numbers of documents. * @public */ export function deserializeStream( data: Buffer | ArrayBufferView | ArrayBuffer, startIndex: number, numberOfDocuments: number, documents: Document[], docStartIndex: number, options: DeserializeOptions ): number { const internalOptions = Object.assign( { allowObjectSmallerThanBufferSize: true, index: 0 }, options ); const bufferData = ensureBuffer(data); let index = startIndex; // Loop over all documents for (let i = 0; i < numberOfDocuments; i++) { // Find size of the document const size = bufferData[index] | (bufferData[index + 1] << 8) | (bufferData[index + 2] << 16) | (bufferData[index + 3] << 24); // Update options with index internalOptions.index = index; // Parse the document at this point documents[docStartIndex + i] = internalDeserialize(bufferData, internalOptions); // Adjust index by the document size index = index + size; } // Return object containing end index of parsing and list of documents return index; } /** * BSON default export * @deprecated Please use named exports * @privateRemarks * We want to someday deprecate the default export, * so none of the new TS types are being exported on the default * @public */ const BSON = { Binary, Code, DBRef, Decimal128, Double, Int32, Long, UUID, Map, MaxKey, MinKey, ObjectId, ObjectID: ObjectId, BSONRegExp, BSONSymbol, Timestamp, EJSON, setInternalBufferSize, serialize, serializeWithBufferAndIndex, deserialize, calculateObjectSize, deserializeStream, BSONError, BSONTypeError }; export default BSON;