@undercroft/pulse-frame
Version:
Low-level WebSocket framing library implementing RFC 6455. Supports payload masking, control frames, and binary/text handling.
3 lines (2 loc) • 6.83 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).PulseFrame=t()}(this,(function(){"use strict";function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t,r;return e(function(){if(r)return t;r=1;var e,n=Object.defineProperty,o=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,s={};function l(e,t){let r=Buffer.allocUnsafe(e.length);for(let n=0;n<e.length;n++)r[n]=e[n]^t[n%4];return r}((e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})})(s,{createFrame:()=>d,createFrameFromBuffer:()=>m,createFrameFromControlCode:()=>y,createFrameFromText:()=>v,frameToBuffer:()=>k}),e=s,t=((e,t,r,s)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let l of i(t))!a.call(e,l)&&l!==r&&n(e,l,{get:()=>t[l],enumerable:!(s=o(t,l))||s.enumerable});return e})(n({},"__esModule",{value:!0}),e);var f,h=((f=h||{})[f.CONTINUATION=0]="CONTINUATION",f[f.TEXT=1]="TEXT",f[f.BINARY=2]="BINARY",f[f.CLOSE=8]="CLOSE",f[f.PING=9]="PING",f[f.PONG=10]="PONG",f),u=class{constructor(e,t,r,n){this.header=e,this.payload=t,this.extensionData=r,this.applicationData=n,this.masked=1===e.mask&&!!e.maskingKey}setApplicationData(e){this.applicationData=e}getPayload(){return this.applicationData??this.payload}getPayloadString(){return this.applicationData?.toString("utf8")??""}getExtensionData(){return this.extensionData}getHeader(){return this.header}isMasked(){return this.masked}isFinal(){return 1===this.header.fin}getOpcode(){return this.header.opcode}isText(){return 1===this.header.opcode}isBinary(){return 2===this.header.opcode}isContinuation(){return 0===this.header.opcode}isControl(){return this.header.opcode>=8}isPing(){return 9===this.header.opcode}isPong(){return 10===this.header.opcode}isClose(){return 8===this.header.opcode}isData(){return this.isText()||this.isBinary()}toJSON(){return{fin:this.header.fin,rsv1:this.header.rsv1,rsv2:this.header.rsv2,rsv3:this.header.rsv3,opcode:h[this.header.opcode]??`Unknown(${this.header.opcode})`,mask:this.header.mask,length:this.header.length,isControl:this.isControl(),isText:this.isText(),isBinary:this.isBinary(),isClose:this.isClose(),isPing:this.isPing(),isPong:this.isPong(),isMasked:this.masked,applicationDataLength:this.applicationData?.length??0,extensionDataLength:this.extensionData?.length??0}}toString(){return`PulseFrame[opcode=${h[this.header.opcode]??this.header.opcode}, fin=${this.header.fin}, length=${this.header.length}, masked=${this.masked}]`}};function d(e){let t={fin:e.fin??1,rsv1:e.rsv1??0,rsv2:e.rsv2??0,rsv3:e.rsv3??0,mask:e.mask??0,opcode:e.opcode,extensionDataLength:e.extensionDataLength??0,maskingKey:e.maskingKey,length:0},r=e.payloadData??Buffer.alloc(0),n=1===t.mask&&!!t.maskingKey,o=e.extensionData??void 0,i=n?l(r,t.maskingKey):r;return t.length=i.length,new u(t,i,o,i)}var c=class e extends Error{constructor(t){super(t),this.message=t,this.name="PulseFrameError",Object.setPrototypeOf(this,e.prototype)}},g=new TextDecoder("utf-8",{fatal:!0}),p=e=>{if(1===e.length)throw new c("Protocol error: close frame payload too small");if(e.length>=2){let t=e.readUInt16BE(0);if(t<1e3||t>4999)throw new c(`Protocol error: invalid close code ${t}`)}if(e.length>2){let t=e.subarray(2);try{!function(e){g.decode(e)}(t)}catch{throw new c("Protocol error: invalid UTF-8 in close reason")}}};function m(e,t){if(e.length<2)throw new c("Incomplete frame: missing first two bytes");let r=t?.extensionLength??0,n=t?.extensionSupport??{rsv1:!1,rsv2:!1,rsv3:!1},o=function(e,t){let r=e[0],n=e[1];return{fin:(128&r)>>>7,rsv1:(64&r)>>>6,rsv2:(32&r)>>>5,rsv3:(16&r)>>>4,mask:(128&n)>>>7,opcode:15&r,length:127&n,extensionDataLength:t,maskingKey:void 0}}(e,r),i=1===o.mask||!!o.maskingKey;(function(e,t){if(1===e.rsv1&&!t.rsv1)throw new Error("RSV1 is set but not supported by any extension");if(1===e.rsv2&&!t.rsv2)throw new Error("RSV2 is set but not supported by any extension");if(1===e.rsv3&&!t.rsv3)throw new Error("RSV3 is set but not supported by any extension")})(o,n),function(e){let{opcode:t,fin:r}=e;if(!Object.values(h).includes(t))throw new c(`Invalid opcode: ${t}`);let n=t>=8;if(n&&1!==r)throw new c("Protocol error: control frames must not be fragmented (FIN=1)");if(n&&e.length>125)throw new c("Control frame payload too long")}(o);let a=function(e,t,r){if(t<126)return t;if(126===t){if(e.length<r+2)throw new c("Incomplete frame: expected 2 bytes for extended length");return e.readUInt16BE(r)}if(127===t){if(e.length<r+8)throw new c("Incomplete frame: expected 8 bytes for extended length");return Number(e.readBigUInt64BE(r))}throw new c("Invalid payload length")}(e,o.length,2),s=function(e){if(e<126)return 0;if(126===e)return 2;if(127===e)return 8;throw new c("Invalid payload length for extended length")}(o.length);if(i){let t=function(e,t,r){let n=t+r;if(e.length<n)throw new c("Incomplete frame: expected 4 bytes for masking key");return e.subarray(t,n)}(e,2+s,4);o.maskingKey=t}let l=function(e,t,r){let n=t+r;if(e.length<n)throw new c("Incomplete frame: not enough bytes for payload");return e.subarray(t,n)}(e,2+s+(i?4:0),a),f=i?function(e,t){let r=Buffer.allocUnsafe(e.length);for(let n=0;n<e.length;n++)r[n]=e[n]^t[n%4];return r}(l,o.maskingKey):l,d=function(e,t,r){if(0===r)return Buffer.alloc(0);let n=t+r;if(n>e.length)throw new c("Incomplete frame: extension data exceeds buffer length");return e.subarray(t,n)}(f,0,r),g=function(e,t){if(0===t)return e;if(t>e.length)throw new c("Invalid application data length: exceeds buffer size");return e.subarray(t)}(f,r);return 8===o.opcode&&p(g),new u(o,f,d,g)}function y(e,t){let r=Buffer.isBuffer(e)?e:Buffer.alloc(0);if(r.length>125)throw new c("Control frame payload too large (max 125 bytes)");let n={fin:1,rsv1:0,rsv2:0,rsv3:0,mask:0,opcode:t,length:r.length,extensionDataLength:0,maskingKey:void 0};return new u(n,r,void 0,r)}function v(e){let t=Buffer.from(e,"utf8"),r={fin:1,rsv1:0,rsv2:0,rsv3:0,mask:0,opcode:1,length:t.length,extensionDataLength:0,maskingKey:void 0};return new u(r,t,void 0,t)}var w=(e,t)=>{let r=t<126?t:t<65536?126:127;return[e.fin<<7|e.rsv1<<6|e.rsv2<<5|e.rsv3<<4|15&e.opcode,e.mask<<7|r]};function k(e){let t=e.getPayload(),r=t.length,n=function(e){return e<126?0:e<65536?2:8}(r),o=function(e){if(e<126)return Buffer.alloc(0);if(e<65536){let t=Buffer.alloc(2);return t.writeUInt16BE(e,0),t}let t=Buffer.alloc(8);return t.writeBigUInt64BE(BigInt(e),0),t}(r),i=2+n;e.isMasked()&&(i+=4);let a=e.isMasked()?l(t,e.getHeader().maskingKey):t,s=Buffer.alloc(i),[f,h]=w(e.getHeader(),r);return s[0]=f,s[1]=h,o.copy(s,2),e.isMasked()&&e.getHeader().maskingKey.copy(s,2+n),Buffer.concat([s,a])}return t}())}));
//# sourceMappingURL=index.umd.js.map