"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { EQSocketProtocolContentEncoding: () => EQSocketProtocolContentEncoding, EQSocketProtocolContentType: () => EQSocketProtocolContentType, EQSocketProtocolMessageType: () => EQSocketProtocolMessageType, QSocketProtocol: () => QSocketProtocol, QSocketProtocolDecodeError: () => QSocketProtocolDecodeError, QSocketProtocolEncodeError: () => QSocketProtocolEncodeError }); module.exports = __toCommonJS(src_exports); // src/bin/protocol.enums.ts var EQSocketProtocolMessageType = /* @__PURE__ */ ((EQSocketProtocolMessageType2) => { EQSocketProtocolMessageType2[EQSocketProtocolMessageType2["DATA"] = 0] = "DATA"; EQSocketProtocolMessageType2[EQSocketProtocolMessageType2["CONTROL"] = 1] = "CONTROL"; EQSocketProtocolMessageType2[EQSocketProtocolMessageType2["ACK"] = 2] = "ACK"; return EQSocketProtocolMessageType2; })(EQSocketProtocolMessageType || {}); var EQSocketProtocolContentType = /* @__PURE__ */ ((EQSocketProtocolContentType2) => { EQSocketProtocolContentType2[EQSocketProtocolContentType2["UNDEFINED"] = 0] = "UNDEFINED"; EQSocketProtocolContentType2[EQSocketProtocolContentType2["NULL"] = 1] = "NULL"; EQSocketProtocolContentType2[EQSocketProtocolContentType2["BOOLEAN"] = 2] = "BOOLEAN"; EQSocketProtocolContentType2[EQSocketProtocolContentType2["NUMBER"] = 3] = "NUMBER"; EQSocketProtocolContentType2[EQSocketProtocolContentType2["STRING"] = 4] = "STRING"; EQSocketProtocolContentType2[EQSocketProtocolContentType2["JSON"] = 5] = "JSON"; EQSocketProtocolContentType2[EQSocketProtocolContentType2["BUFFER"] = 6] = "BUFFER"; return EQSocketProtocolContentType2; })(EQSocketProtocolContentType || {}); var EQSocketProtocolContentEncoding = /* @__PURE__ */ ((EQSocketProtocolContentEncoding2) => { EQSocketProtocolContentEncoding2[EQSocketProtocolContentEncoding2["RAW"] = 0] = "RAW"; EQSocketProtocolContentEncoding2[EQSocketProtocolContentEncoding2["GZIP"] = 1] = "GZIP"; EQSocketProtocolContentEncoding2[EQSocketProtocolContentEncoding2["DEFLATE"] = 2] = "DEFLATE"; return EQSocketProtocolContentEncoding2; })(EQSocketProtocolContentEncoding || {}); // src/bin/protocol.errors.ts var QSocketProtocolEncodeError = class extends Error { /** * Creates an instance of QSocketProtocolEncodeError. * * @param message - A descriptive error message. * @param originalError - (Optional) The original error that caused this encoding error, if any. */ constructor(message, originalError) { super(message); this.originalError = originalError; this.name = "QSocketProtocolEncodeError"; if (originalError) { this.stack += ` Caused by: ${originalError.stack}`; } } }; var QSocketProtocolDecodeError = class extends Error { /** * Creates an instance of QSocketProtocolDecodeError. * * @param message - A descriptive error message. * @param originalError - (Optional) The original error that caused this decoding error, if any. */ constructor(message, originalError) { super(message); this.originalError = originalError; this.name = "QSocketProtocolDecodeError"; if (originalError) { this.stack += ` Caused by: ${originalError.stack}`; } } }; // src/bin/protocol.helpers.ts var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function"; function isBuffer(obj) { return hasBuffer && Buffer.isBuffer(obj); } // src/bin/protocol.ts var QSocketProtocol = class { /** * @description Initializes the `QSocketProtocol` instance with an optional compressor and a specified maximum size for uncompressed data. * * @param compressor - Optional object implementing `TQSocketProtocolCompressor` for data compression and decompression. * @param maxUncompressedSize - Maximum size in bytes for uncompressed data. Default is 10KB. */ constructor(compressor, maxUncompressedSize = 10 * 1024) { this.compressor = compressor; this.maxUncompressedSize = maxUncompressedSize; } /** * @description Encodes a message into a `Buffer` or `Uint8Array`, applying optional compression if the message exceeds the maximum uncompressed size. * * @param message - A structured protocol message to encode. * @returns A `Promise` resolving to the encoded message as `Buffer` or `Uint8Array`, or an `EncodeError` on failure. */ async to(message) { try { const chunkBuffers = []; for (const chunk of message) { const chunkBuffer = await this.encodeChunk(chunk); const chunkLengthBuffer = this.writeUInt32(chunkBuffer.length); const chunkEntryBuffer = this.concatBuffers([chunkLengthBuffer, chunkBuffer]); chunkBuffers.push(chunkEntryBuffer); } const messageData = this.concatBuffers(chunkBuffers); let compressedMessageData = messageData; let compressionFlag = 0; let compressionFormat = 0 /* RAW */; const uncompressedLength = messageData.length; let compressedLength = messageData.length; if (this.compressor && uncompressedLength > this.maxUncompressedSize) { compressedMessageData = await this.compressor.toGzip(messageData); compressedLength = compressedMessageData.length; compressionFlag = 1; compressionFormat = 1 /* GZIP */; } const compressionFlagByte = this.writeUInt8(compressionFlag); const compressionFormatByte = this.writeUInt8(compressionFormat); const uncompressedLengthBuffer = this.writeUInt32(uncompressedLength); const compressedLengthBuffer = this.writeUInt32(compressedLength); const headerBuffers = [compressionFlagByte, compressionFormatByte, uncompressedLengthBuffer, compressedLengthBuffer]; const finalBuffers = [...headerBuffers, compressedMessageData]; const finalMessageBuffer = this.concatBuffers(finalBuffers); return finalMessageBuffer; } catch (error) { return new QSocketProtocolEncodeError(error.message); } } /** * @description Decodes a message from a `Buffer` or `Uint8Array`, decompressing if necessary, and converts it into structured protocol chunks. * * @param buffer - Encoded message data. * @returns A `Promise` resolving to a structured protocol message, or a `DecodeError` on failure. */ async from(buffer) { try { let offset = 0; if (buffer.length < 10) { throw new QSocketProtocolDecodeError("Buffer too small to contain header"); } const compressionFlag = this.readUInt8(buffer, offset); offset += 1; const compressionFormat = this.readUInt8(buffer, offset); offset += 1; const uncompressedLength = this.readUInt32(buffer, offset); offset += 4; const compressedLength = this.readUInt32(buffer, offset); offset += 4; if (buffer.length < offset + compressedLength) { throw new QSocketProtocolDecodeError("Buffer too small for compressed data"); } const compressedMessageData = buffer.subarray(offset, offset + compressedLength); offset += compressedLength; if (compressedMessageData.length !== compressedLength) { throw new QSocketProtocolDecodeError("Compressed data length mismatch"); } let messageData = compressedMessageData; if (compressionFlag === 1) { if (!this.compressor) { throw new QSocketProtocolDecodeError("Compressor not available for decompression"); } if (compressionFormat === 1 /* GZIP */) { messageData = await this.compressor.fromGzip(compressedMessageData); } else if (compressionFormat === 2 /* DEFLATE */) { messageData = await this.compressor.fromDeflate(compressedMessageData); } else { throw new QSocketProtocolDecodeError("Unknown compression format"); } if (messageData.length !== uncompressedLength) { throw new QSocketProtocolDecodeError("Uncompressed data length mismatch after decompression"); } } else { if (messageData.length !== uncompressedLength) { throw new QSocketProtocolDecodeError("Uncompressed data length mismatch"); } } let messageOffset = 0; const message = []; while (messageOffset < messageData.length) { if (messageData.length - messageOffset < 4) { throw new QSocketProtocolDecodeError("Insufficient data for chunk length"); } const chunkLength = this.readUInt32(messageData, messageOffset); messageOffset += 4; if (messageData.length - messageOffset < chunkLength) { throw new QSocketProtocolDecodeError("Insufficient data for chunk"); } const chunkBuffer = messageData.subarray(messageOffset, messageOffset + chunkLength); messageOffset += chunkLength; const chunk = await this.decodeChunk(chunkBuffer); message.push(chunk); } if (messageOffset !== messageData.length) { throw new QSocketProtocolDecodeError("Extra data after message parsing"); } return message; } catch (error) { return new QSocketProtocolDecodeError(error.message); } } /** * @description Encodes an individual message chunk, converting metadata and payload into `Buffer` or `Uint8Array` with optional compression. * * @param chunk - A protocol chunk with metadata and payload data. * @returns A `Promise` resolving to the encoded chunk as `Buffer` or `Uint8Array`. */ async encodeChunk(chunk) { if (!chunk.meta || typeof chunk.meta !== "object") { throw new Error("Invalid chunk meta"); } const metaString = JSON.stringify(chunk.meta); const metaBuffer = this.encodeString(metaString); const metaLengthBuffer = this.writeUInt32(metaBuffer.length); const dataBuffer = await this.encodePayloadData(chunk.payload.data, chunk.payload["Content-Type"]); let payloadBuffer = dataBuffer; if (chunk.payload["Content-Encoding"] === 1 /* GZIP */) { if (this.compressor) { payloadBuffer = await this.compressor.toGzip(dataBuffer); } else { throw new Error("Compressor not available for GZIP encoding"); } } else if (chunk.payload["Content-Encoding"] === 2 /* DEFLATE */) { if (this.compressor) { payloadBuffer = await this.compressor.toDeflate(dataBuffer); } else { throw new Error("Compressor not available for DEFLATE encoding"); } } else if (chunk.payload["Content-Encoding"] !== 0 /* RAW */) { throw new Error("Unknown Content-Encoding"); } const payloadLengthBuffer = this.writeUInt32(payloadBuffer.length); const contentTypeByte = this.writeUInt8(chunk.payload["Content-Type"]); const contentEncodingByte = this.writeUInt8(chunk.payload["Content-Encoding"]); const buffers = [metaLengthBuffer, metaBuffer, payloadLengthBuffer, contentTypeByte, contentEncodingByte, payloadBuffer]; const chunkBuffer = this.concatBuffers(buffers); return chunkBuffer; } /** * @description Decodes a chunk from `Buffer` or `Uint8Array` format back into a protocol chunk, decompressing if necessary. * * @param chunkBuffer - Encoded chunk data. * @returns A `Promise` resolving to a structured protocol chunk. */ async decodeChunk(chunkBuffer) { let offset = 0; if (chunkBuffer.length < 4) { throw new Error("Chunk buffer too small for meta length"); } const metaLength = this.readUInt32(chunkBuffer, offset); offset += 4; if (chunkBuffer.length < offset + metaLength) { throw new Error("Chunk buffer too small for metadata"); } const metaBuffer = chunkBuffer.subarray(offset, offset + metaLength); offset += metaLength; const metaString = this.decodeString(metaBuffer); const meta = JSON.parse(metaString); if (chunkBuffer.length < offset + 4) { throw new Error("Chunk buffer too small for payload length"); } const payloadLength = this.readUInt32(chunkBuffer, offset); offset += 4; if (chunkBuffer.length < offset + 2) { throw new Error("Chunk buffer too small for content type and encoding"); } const contentType = this.readUInt8(chunkBuffer, offset); offset += 1; const contentEncoding = this.readUInt8(chunkBuffer, offset); offset += 1; if (chunkBuffer.length < offset + payloadLength) { throw new Error("Chunk buffer too small for payload data"); } const payloadBuffer = chunkBuffer.subarray(offset, offset + payloadLength); offset += payloadLength; let dataBuffer = payloadBuffer; if (contentEncoding === 1 /* GZIP */) { if (!this.compressor) { throw new Error("Compressor not available for decompression"); } dataBuffer = await this.compressor.fromGzip(payloadBuffer); } else if (contentEncoding === 2 /* DEFLATE */) { if (!this.compressor) { throw new Error("Compressor not available for decompression"); } dataBuffer = await this.compressor.fromDeflate(payloadBuffer); } else if (contentEncoding !== 0 /* RAW */) { throw new Error("Unknown Content-Encoding"); } const data = this.decodePayloadData(dataBuffer, contentType); const chunk = { meta, payload: { data, "Content-Type": contentType, "Content-Encoding": contentEncoding } }; return chunk; } /** * @description Encodes payload data according to its specified content type, converting it into a `Buffer` or `Uint8Array`. * * @param data - The payload data to encode. * @param contentType - Content type indicating the format of `data`. * @returns A `Promise` resolving to the encoded data as `Buffer` or `Uint8Array`. */ async encodePayloadData(data, contentType) { switch (contentType) { case 0 /* UNDEFINED */: return new Uint8Array(0); case 1 /* NULL */: return new Uint8Array(0); case 2 /* BOOLEAN */: return this.writeUInt8(data ? 1 : 0); case 3 /* NUMBER */: return this.writeDouble(data); case 4 /* STRING */: return this.encodeString(data); case 5 /* JSON */: return this.encodeString(JSON.stringify(data)); case 6 /* BUFFER */: return isBuffer(data) ? data : new Uint8Array(data); default: throw new Error("Unknown content type"); } } /** * @description Decodes payload data from a `Buffer` or `Uint8Array` based on its specified content type. * * @param buffer - Encoded data buffer. * @param contentType - Content type indicating the format of the buffer. * @returns The decoded data in its original format. */ decodePayloadData(buffer, contentType) { switch (contentType) { case 0 /* UNDEFINED */: return void 0; case 1 /* NULL */: return null; case 2 /* BOOLEAN */: const value = this.readUInt8(buffer, 0); return value !== 0; case 3 /* NUMBER */: return this.readDouble(buffer, 0); case 4 /* STRING */: return this.decodeString(buffer); case 5 /* JSON */: return JSON.parse(this.decodeString(buffer)); case 6 /* BUFFER */: return buffer; default: throw new Error("Unknown content type"); } } /** * @description Encodes a string into a UTF-8 `Buffer` or `Uint8Array`, depending on environment support. * * @param str - The string to encode. * @returns Encoded UTF-8 representation as `Buffer` or `Uint8Array`. */ encodeString(str) { if (typeof TextEncoder !== "undefined") { const encoder = new TextEncoder(); return encoder.encode(str); } else if (hasBuffer) { return Buffer.from(str, "utf8"); } else { const utf8 = unescape(encodeURIComponent(str)); const result = new Uint8Array(utf8.length); for (let i = 0; i < utf8.length; i++) { result[i] = utf8.charCodeAt(i); } return result; } } /** * @description Decodes a UTF-8 encoded `Buffer` or `Uint8Array` back into a string. * * @param buffer - UTF-8 encoded buffer. * @returns The decoded string. */ decodeString(buffer) { if (typeof TextDecoder !== "undefined") { const decoder = new TextDecoder("utf8"); return decoder.decode(buffer); } else if (hasBuffer && isBuffer(buffer)) { return buffer.toString("utf8"); } else { let result = ""; for (let i = 0; i < buffer.length; i++) { result += String.fromCharCode(buffer[i]); } return decodeURIComponent(escape(result)); } } /** * @description Encodes a 32-bit unsigned integer into a `Buffer` or `Uint8Array` in big-endian format. * * @param value - The integer to encode. * @returns The encoded integer as `Buffer` or `Uint8Array`. */ writeUInt32(value) { if (hasBuffer) { const buffer = Buffer.alloc(4); buffer.writeUInt32BE(value, 0); return buffer; } else { const buffer = new Uint8Array(4); const view = new DataView(buffer.buffer); view.setUint32(0, value, false); return buffer; } } /** * @description Reads a 32-bit unsigned integer from a `Buffer` or `Uint8Array` in big-endian format. * * @param buffer - The buffer containing the integer. * @param offset - The offset position within the buffer to start reading. * @returns The decoded integer. */ readUInt32(buffer, offset) { if (hasBuffer && isBuffer(buffer)) { return buffer.readUInt32BE(offset); } else { const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 4); return view.getUint32(0, false); } } /** * @description Writes an 8-bit unsigned integer into a `Buffer` or `Uint8Array`. * * @param value - The integer to write. * @returns The encoded integer as `Buffer` or `Uint8Array`. */ writeUInt8(value) { const buffer = new Uint8Array(1); buffer[0] = value & 255; return buffer; } /** * @description Reads an 8-bit unsigned integer from a `Buffer` or `Uint8Array`. * * @param buffer - The buffer containing the integer. * @param offset - The offset position within the buffer to start reading. * @returns The decoded integer. */ readUInt8(buffer, offset) { return buffer[offset]; } /** * @description Encodes a double-precision floating-point number into a `Buffer` or `Uint8Array`. * * @param value - The floating-point number to encode. * @returns The encoded value as `Buffer` or `Uint8Array`. */ writeDouble(value) { if (hasBuffer) { const buffer = Buffer.alloc(8); buffer.writeDoubleBE(value, 0); return buffer; } else { const buffer = new Uint8Array(8); const view = new DataView(buffer.buffer); view.setFloat64(0, value, false); return buffer; } } /** * @description Reads a double-precision floating-point number from a `Buffer` or `Uint8Array`. * * @param buffer - The buffer containing the double value. * @param offset - The offset position within the buffer to start reading. * @returns The decoded floating-point number. */ readDouble(buffer, offset) { if (hasBuffer && isBuffer(buffer)) { return buffer.readDoubleBE(offset); } else { const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 8); return view.getFloat64(0, false); } } /** * @description Concatenates multiple `Buffer` or `Uint8Array` instances into a single `Buffer` or `Uint8Array`. * * @param buffers - An array of buffers to concatenate. * @returns A single concatenated `Buffer` or `Uint8Array`. */ concatBuffers(buffers) { if (hasBuffer) { return Buffer.concat(buffers.map((buf) => isBuffer(buf) ? buf : Buffer.from(buf))); } else { let totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0); const result = new Uint8Array(totalLength); let offset = 0; for (const buf of buffers) { result.set(buf, offset); offset += buf.length; } return result; } } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { EQSocketProtocolContentEncoding, EQSocketProtocolContentType, EQSocketProtocolMessageType, QSocketProtocol, QSocketProtocolDecodeError, QSocketProtocolEncodeError }); //# sourceMappingURL=index.cjs.map