webserial-core
Version:
A strongly-typed, event-driven, abstract TypeScript library for the Web Serial API with custom parsers, command queue, handshake validation, and auto-reconnect.
2 lines • 26.3 kB
JavaScript
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class{listeners={};on(e,t){return this.listeners[e]||(this.listeners[e]=new Set),this.listeners[e].add(t),this}off(e,t){return this.listeners[e]&&this.listeners[e].delete(t),this}emit(e,...t){let n=this.listeners[e];if(!n||n.size===0)return!1;for(let e of n)e(...t);return!0}},t=class{static instances=new Set;static portInstanceMap=new WeakMap;static getInstances(){return Array.from(this.instances)}static register(e){this.instances.add(e)}static unregister(e){this.instances.delete(e)}static isPortInUse(e,t){let n=this.portInstanceMap.get(e);return n!==void 0&&n!==t}static lockPort(e,t){this.portInstanceMap.set(e,t)}static unlockPort(e){this.portInstanceMap.delete(e)}},n=class{queue=[];isProcessing=!1;isPaused=!0;timeoutId=null;commandTimeout;onSend;onTimeout;constructor(e){this.commandTimeout=e.commandTimeout,this.onSend=e.onSend,this.onTimeout=e.onTimeout}get queueSize(){return this.queue.length}enqueue(e){this.queue.push(e),this.tryProcessNext()}advance(){this.clearCommandTimeout(),this.isProcessing=!1,this.tryProcessNext()}pause(){this.isPaused=!0,this.clearCommandTimeout(),this.isProcessing=!1}resume(){this.isPaused=!1,this.tryProcessNext()}clear(){this.queue=[],this.clearCommandTimeout(),this.isProcessing=!1}snapshot(){return[...this.queue]}restore(e){this.queue=[...e,...this.queue]}tryProcessNext(){if(this.isPaused||this.isProcessing||this.queue.length===0)return;this.isProcessing=!0;let e=this.queue.shift();this.commandTimeout>0&&(this.timeoutId=setTimeout(()=>{this.timeoutId=null,this.onTimeout(e),this.advance()},this.commandTimeout)),this.onSend(e).catch(()=>{this.advance()})}clearCommandTimeout(){this.timeoutId!==null&&(clearTimeout(this.timeoutId),this.timeoutId=null)}},r=class e extends Error{constructor(t){super(t),this.name=`SerialPortConflictError`,Object.setPrototypeOf(this,e.prototype)}},i=class e extends Error{constructor(t){super(t),this.name=`SerialPermissionError`,Object.setPrototypeOf(this,e.prototype)}},a=class e extends Error{constructor(t){super(t),this.name=`SerialTimeoutError`,Object.setPrototypeOf(this,e.prototype)}},o=class e extends Error{constructor(t){super(t),this.name=`SerialReadError`,Object.setPrototypeOf(this,e.prototype)}},s=class e extends Error{constructor(t){super(t),this.name=`SerialWriteError`,Object.setPrototypeOf(this,e.prototype)}},c=class r extends e{port=null;reader=null;writer=null;queue;options;isConnecting=!1;abortController=null;userInitiatedDisconnect=!1;reconnectTimerId=null;isHandshaking=!1;static customProvider=null;static polyfillOptions;constructor(e){super(),this.options={baudRate:e.baudRate,dataBits:e.dataBits??8,stopBits:e.stopBits??1,parity:e.parity??`none`,bufferSize:e.bufferSize??255,flowControl:e.flowControl??`none`,filters:e.filters??[],commandTimeout:e.commandTimeout??0,parser:e.parser,autoReconnect:e.autoReconnect??!1,autoReconnectInterval:e.autoReconnectInterval??1500,handshakeTimeout:e.handshakeTimeout??2e3,provider:e.provider,polyfillOptions:e.polyfillOptions},this.queue=new n({commandTimeout:this.options.commandTimeout,onSend:async e=>{await this.writeToPort(e),this.emit(`serial:sent`,e,this)},onTimeout:e=>{this.emit(`serial:timeout`,e,this)}}),this.on(`serial:data`,()=>{this.queue.advance()}),t.register(this)}async handshake(){return!0}async connect(){if(!this.isConnecting&&!this.port){this.isConnecting=!0,this.emit(`serial:connecting`,this);try{let e=this.getSerial();if(!e)throw Error(`Web Serial API is not supported in this browser. Use AbstractSerialDevice.setProvider() to set a WebUSB polyfill.`);if(this.port=await this.findAndValidatePort(),!this.port){let t;try{t=await e.requestPort({filters:this.options.filters},this.options.polyfillOptions??r.polyfillOptions)}catch(e){throw e instanceof DOMException&&(e.name===`NotFoundError`||e.name===`SecurityError`||e.name===`AbortError`)?new i(e instanceof Error?e.message:String(e)):e instanceof Error?e:Error(String(e))}if(!await this.openAndHandshake(t))throw Error(`Handshake failed: the selected device did not respond correctly.`);this.port=t}this.abortController=new AbortController,this.queue.resume(),this.emit(`serial:connected`,this)}catch(e){if(e instanceof i?this.emit(`serial:need-permission`,this):this.emit(`serial:error`,e instanceof Error?e:Error(String(e)),this),this.port){t.unlockPort(this.port);try{await this.port.close()}catch{}this.port=null}throw e}finally{this.isConnecting=!1}}}async disconnect(){this.port&&(this.userInitiatedDisconnect=!0,this.stopReconnecting(),await this.cleanupPort())}isConnected(){return!!(this.port&&this.port.connected&&this.port.readable&&this.port.writable)}isDisconnected(){return!this.isConnected()}async cleanupPort(){if(this.port){this.queue.pause(),this.abortController?.abort(),this.abortController=null;try{let e=this.reader,t=this.writer;if(this.reader=null,this.writer=null,e){try{await e.cancel()}catch{}try{e.releaseLock()}catch{}}if(t){try{await t.close()}catch{}try{t.releaseLock()}catch{}}try{await this.port.close()}catch{}}catch(e){this.emit(`serial:error`,e instanceof Error?e:Error(String(e)),this)}finally{this.port&&t.unlockPort(this.port),this.port=null,this.options.parser?.reset?.(),this.emit(`serial:disconnected`,this),!this.userInitiatedDisconnect&&this.options.autoReconnect&&this.startReconnecting(),this.userInitiatedDisconnect=!1}}}async forget(){await this.disconnect(),this.port&&typeof this.port.forget==`function`&&await this.port.forget(),t.unregister(this)}async send(e){let t;t=typeof e==`string`?new TextEncoder().encode(e):e,t.length>0&&this.queue.enqueue(t)}clearQueue(){this.queue.clear(),this.emit(`serial:queue-empty`,this)}async writeToPort(e){if(!this.port||!this.port.writable)throw new s(`Port not writable.`);this.writer=this.port.writable.getWriter();try{await this.writer.write(e)}catch(e){throw new s(e instanceof Error?e.message:String(e))}finally{this.writer.releaseLock(),this.writer=null}}async readLoop(){if(!(!this.port||!this.port.readable)&&!this.reader){this.reader=this.port.readable.getReader();try{for(;;){let{value:e,done:t}=await this.reader.read();if(t)break;e&&(this.options.parser?this.options.parser.parse(e,e=>{this.emit(`serial:data`,e,this)}):this.emit(`serial:data`,e,this))}}catch(e){if(this.port)throw new o(e instanceof Error?e.message:String(e))}finally{if(this.reader){try{this.reader.releaseLock()}catch{}this.reader=null}}}}async openAndHandshake(e){let n=this;if(t.isPortInUse(e,n))return!1;t.lockPort(e,n);try{await e.open({baudRate:this.options.baudRate,dataBits:this.options.dataBits,stopBits:this.options.stopBits,parity:this.options.parity,bufferSize:this.options.bufferSize,flowControl:this.options.flowControl})}catch(n){throw t.unlockPort(e),n instanceof Error?n:Error(String(n))}this.port=e,this.abortController=new AbortController;let r=this.queue.snapshot();this.isHandshaking=!0,this.readLoop().catch(e=>{!this.isHandshaking&&this.port&&(this.emit(`serial:error`,e,this),this.cleanupPort())}),this.queue.resume();try{let t=await this.runHandshakeWithTimeout();return this.isHandshaking=!1,t?(this.queue.pause(),this.queue.clear(),this.queue.restore(r),this.options.parser?.reset?.(),!0):(await this.teardownHandshake(e,r),!1)}catch{return this.isHandshaking=!1,await this.teardownHandshake(e,r),!1}}async teardownHandshake(e,n){this.queue.pause(),this.queue.clear(),this.queue.restore(n),await this.stopReader(),this.port=null,this.abortController=null,this.options.parser?.reset?.();try{await e.close()}catch{}t.unlockPort(e)}async stopReader(){let e=this.reader;if(this.reader=null,e){try{await e.cancel()}catch{}try{e.releaseLock()}catch{}}}async runHandshakeWithTimeout(){let e=this.options.handshakeTimeout??2e3;return Promise.race([this.handshake(),new Promise(t=>setTimeout(()=>t(!1),e))])}async findAndValidatePort(){let e=this.getSerial();if(!e)return null;let n=await e.getPorts(this.options.polyfillOptions??r.polyfillOptions);if(n.length===0)return null;let i=this.options.filters??[],a=this;for(let e of n)if(!t.isPortInUse(e,a)){if(i.length>0){let t=e.getInfo();if(!i.some(e=>{let n=e.usbVendorId===void 0||e.usbVendorId===t.usbVendorId,r=e.usbProductId===void 0||e.usbProductId===t.usbProductId;return n&&r}))continue}try{if(await this.openAndHandshake(e))return e}catch{}}return null}startReconnecting(){this.reconnectTimerId||=(this.emit(`serial:reconnecting`,this),setInterval(async()=>{if(this.port||this.isConnecting){this.stopReconnecting();return}try{let e=await this.findAndValidatePort();e&&(this.stopReconnecting(),await this.reconnect(e))}catch{}},this.options.autoReconnectInterval))}stopReconnecting(){this.reconnectTimerId&&=(clearInterval(this.reconnectTimerId),null)}async reconnect(e){if(!(this.isConnecting||this.port)){this.isConnecting=!0,this.emit(`serial:connecting`,this);try{this.port=e,this.abortController=new AbortController,this.queue.resume(),this.emit(`serial:connected`,this)}catch(e){this.emit(`serial:error`,e instanceof Error?e:Error(String(e)),this),this.port&&=(t.unlockPort(this.port),null),this.options.autoReconnect&&this.startReconnecting()}finally{this.isConnecting=!1}}}static getInstances(){return t.getInstances()}static async connectAll(){let e=t.getInstances();for(let t of e)try{await t.connect()}catch{}}static setProvider(e,t){r.customProvider=e,r.polyfillOptions=t}getSerial(){return this.options.provider?this.options.provider:r.customProvider?r.customProvider:typeof navigator<`u`&&navigator.serial?navigator.serial:null}};function l(e=50){let t=new Uint8Array,n=null;function r(e){for(;!(t.length<2);){let n=t[1]+5;if(t.length<n)break;e(t.slice(0,n)),t=t.slice(n)}}return{parse(i,a){n!==null&&(clearTimeout(n),n=null);let o=new Uint8Array(t.length+i.length);o.set(t),o.set(i,t.length),t=o,r(a),t.length>0&&(n=setTimeout(()=>{t=new Uint8Array,n=null},e))},reset(){n!==null&&(clearTimeout(n),n=null),t=new Uint8Array}}}function u(e){return typeof e==`string`?new TextEncoder().encode(e):e instanceof Uint8Array?e:new Uint8Array(e)}function d(e,t){if(t.length===0)return 0;outer:for(let n=0;n<=e.length-t.length;n++){for(let r=0;r<t.length;r++)if(e[n+r]!==t[r])continue outer;return n}return-1}function f(e,t){let n=t?.includeDelimiter??!1,r=u(e);if(typeof e==`string`){let e=new Uint8Array,t=new TextDecoder;return{parse(i,a){let o=new Uint8Array(e.length+i.length);o.set(e),o.set(i,e.length),e=o;let s;for(;(s=d(e,r))!==-1;){let i=n?s+r.length:s;a(t.decode(e.slice(0,i))),t=new TextDecoder,e=e.slice(s+r.length)}},reset(){e=new Uint8Array,t=new TextDecoder}}}let i=new Uint8Array;return{parse(e,t){let a=new Uint8Array(i.length+e.length);a.set(i),a.set(e,i.length),i=a;let o;for(;(o=d(i,r))!==-1;){let e=n?o+r.length:o;t(i.slice(0,e)),i=i.slice(o+r.length)}},reset(){i=new Uint8Array}}}function p(e){if(e<=0)throw Error(`FixedLengthParser: length must be greater than 0`);let t=new Uint8Array;return{parse(n,r){let i=new Uint8Array(t.length+n.length);for(i.set(t),i.set(n,t.length),t=i;t.length>=e;)r(t.slice(0,e)),t=t.slice(e)},reset(){t=new Uint8Array}}}function m(e){if(e.interval<=0)throw Error(`InterByteTimeoutParser: interval must be greater than 0`);let t=e.maxBufferSize??65536,n=new Uint8Array,r=null,i=null;function a(){r!==null&&(clearTimeout(r),r=null),n.length>0&&i!==null&&(i(n.slice()),n=new Uint8Array)}return{parse(o,s){i=s,r!==null&&(clearTimeout(r),r=null);let c=new Uint8Array(n.length+o.length);if(c.set(n),c.set(o,n.length),n=c,n.length>=t){a();return}r=setTimeout(()=>{r=null,a()},e.interval)},reset(){r!==null&&(clearTimeout(r),r=null),n=new Uint8Array,i=null}}}function h(e){let t=e?.delimiter??170,n=e?.packetOverhead??2,r=e?.lengthBytes??1,i=e?.lengthOffset??1,a=e?.maxLen??255;if(i+r>n)throw Error(`PacketLengthParser: lengthOffset + lengthBytes must not exceed packetOverhead`);let o=new Uint8Array;return{parse(e,s){let c=new Uint8Array(o.length+e.length);for(c.set(o),c.set(e,o.length),o=c;;){let e=o.indexOf(t);if(e===-1){o=new Uint8Array;break}e>0&&(o=o.slice(e));let c=i+r;if(o.length<c)break;let l=0;for(let e=0;e<r;e++)l=l<<8|o[i+e];if(l>a){o=o.slice(1);continue}let u=l+n;if(o.length<u)break;s(o.slice(0,u)),o=o.slice(u)}},reset(){o=new Uint8Array}}}function g(){return{parse(e,t){t(e)},reset(){}}}function _(e,t){if(t.length===0)return 0;outer:for(let n=0;n<=e.length-t.length;n++){for(let r=0;r<t.length;r++)if(e[n+r]!==t[r])continue outer;return n}return-1}function v(e){let t=e?.encoding??`utf-8`,n=e?.includeDelimiter??!1,r=e?.delimiter??`
`,i;i=typeof r==`string`?new TextEncoder().encode(r):r instanceof Uint8Array?r:new Uint8Array(r);let a=new Uint8Array;return{parse(e,r){let o=new Uint8Array(a.length+e.length);o.set(a),o.set(e,a.length),a=o;let s;for(;(s=_(a,i))!==-1;){let e=n?s+i.length:s;r(new TextDecoder(t).decode(a.slice(0,e))),a=a.slice(s+i.length)}},reset(){a=new Uint8Array}}}function y(e,t){if(t.length===0)return 0;outer:for(let n=0;n<=e.length-t.length;n++){for(let r=0;r<t.length;r++)if(e[n+r]!==t[r])continue outer;return n}return-1}function b(e){let t=e.delimiter,n;n=typeof t==`string`?new TextEncoder().encode(t):t instanceof Uint8Array?t:new Uint8Array(t);let r=!1,i=new Uint8Array;return{parse(t,a){if(r){a(t);return}let o=new Uint8Array(i.length+t.length);o.set(i),o.set(t,i.length),i=o;let s=y(i,n);if(s===-1)return;r=!0,e.onReady?.();let c=i.slice(s+n.length);i=new Uint8Array,c.length>0&&a(c)},reset(){r=!1,i=new Uint8Array}}}function x(e){let t=e.regex instanceof RegExp?e.regex:new RegExp(e.regex),n=e.encoding??`utf-8`,r=``;return{parse(e,i){let a=new TextDecoder(n);r+=a.decode(e);let o=r.split(t);r=o.pop()??``;for(let e of o)i(e)},reset(){r=``}}}var S={END:192,ESC:219,ESC_END:220,ESC_ESC:221};function C(e){let t=e?.END??S.END,n=e?.ESC??S.ESC,r=e?.ESC_END??S.ESC_END,i=e?.ESC_ESC??S.ESC_ESC,a=e?.START,o=e?.ESC_START??n,s=[],c=!1,l=a===void 0;return{parse(e,u){for(let d=0;d<e.length;d++){let f=e[d];if(!l){f===a&&(l=!0);continue}if(f===t){s.length>0&&(u(new Uint8Array(s)),s=[]),a!==void 0&&(l=!1),c=!1;continue}if(c){c=!1,f===r?s.push(t):f===i?s.push(n):a!==void 0&&f===o?s.push(a):s.push(f);continue}if(f===n){c=!0;continue}s.push(f)}},reset(){s=[],c=!1,l=a===void 0}}}function ee(e,t){let n=t?.END??S.END,r=t?.ESC??S.ESC,i=t?.ESC_END??S.ESC_END,a=t?.ESC_ESC??S.ESC_ESC,o=t?.START,s=t?.ESC_START??r,c=t?.bluetoothQuirk??!1,l=[];c&&l.push(n);for(let t=0;t<e.length;t++){let c=e[t];c===n?l.push(r,i):c===r?l.push(r,a):o!==void 0&&c===o?l.push(r,s):l.push(c)}return l.push(n),new Uint8Array(l)}function te(e){let t=e?.timeCodeFieldLength??0,n=e?.ancillaryDataFieldLength??0,r=new Uint8Array;function i(e){let r=e[0],i=e[1],a=e[2],o=e[3],s=e[4],c=e[5],l=r>>5&7,u=r>>4&1,d=r>>3&1,f=(r&7)<<8|i,p=a>>6&3,m=(a&63)<<8|o,h=s<<8|c,g={versionNumber:l,identification:{apid:f,secondaryHeader:d,type:u},sequenceControl:{packetName:m,sequenceFlags:p},dataLength:h},_,v=6;if(d===1){_={};let r=new TextDecoder(`latin1`);t>0&&(_.timeCode=r.decode(e.slice(v,v+t)),v+=t),n>0&&(_.ancillaryData=r.decode(e.slice(v,v+n)),v+=n)}let y=new TextDecoder(`latin1`).decode(e.slice(v));return{header:g,secondaryHeader:_,data:y}}return{parse(e,t){let n=new Uint8Array(r.length+e.length);for(n.set(r),n.set(e,r.length),r=n;r.length>=6;){let e=6+(r[4]<<8|r[5])+1;if(r.length<e)break;t(i(r.slice(0,e))),r=r.slice(e)}},reset(){r=new Uint8Array}}}var w=32,T=34,E=0,D=30,O=3,k=7,A=1,ne=0,re=771,ie=768,j=255,M=8,N=`none`,P=1,F=[16,8,7,6,5],I=[1,2],L=[`none`,`even`,`odd`],R=[`none`,`odd`,`even`],z=[1,1.5,2],B={usbControlInterfaceClass:2,usbTransferInterfaceClass:10,protocol:void 0};function V(e,t){let n=e.configurations[0];if(!n)return null;for(let e of n.interfaces)if(e.alternates[0]?.interfaceClass===t)return e;return null}function H(e,t){let n=e.configurations[0];if(!n)return null;for(let e of n.interfaces){let n=e.alternates[0];if(!n||n.interfaceClass!==t)continue;let r=n.endpoints.some(e=>e.direction===`in`),i=n.endpoints.some(e=>e.direction===`out`);if(r&&i)return e}return null}function U(e,t){let n=e.alternates[0];if(n){for(let e of n.endpoints)if(e.direction===t)return e}throw TypeError(`Interface ${e.interfaceNumber} does not have an ${t} endpoint.`)}function W(e,t){return t===2?`cdc_acm`:e.vendorId===4292?`cp210x`:`none`}var G=class{device_;endpoint_;onError_;constructor(e,t,n){this.device_=e,this.endpoint_=t,this.onError_=n}pull(e){(async()=>{let t=this.endpoint_.packetSize;try{let n=await this.device_.transferIn(this.endpoint_.endpointNumber,t);if(n.status!==`ok`){e.error(`USB error: ${n.status}`),this.onError_();return}if(n.data?.buffer&&n.data.byteLength>0){let t=new Uint8Array(n.data.buffer,n.data.byteOffset,n.data.byteLength);t.length>0&&e.enqueue(t)}}catch(t){e.error(String(t)),this.onError_()}})()}},K=class{device_;endpoint_;onError_;constructor(e,t,n){this.device_=e,this.endpoint_=t,this.onError_=n}async write(e,t){try{let n=await this.device_.transferOut(this.endpoint_.endpointNumber,e.buffer);n.status!==`ok`&&(t.error(n.status),this.onError_())}catch(e){t.error(String(e)),this.onError_()}}},q=class{device_;protocol_;controlInterface_;transferInterface_;inEndpoint_;outEndpoint_;serialOptions_;readable_=null;writable_=null;cdcOutputSignals_={dataTerminalReady:!1,requestToSend:!1,break:!1};constructor(e,t){this.device_=e;let n={...B,...t};this.protocol_=n.protocol??W(e,n.usbControlInterfaceClass);let r=n.usbControlInterfaceClass,i=n.usbTransferInterfaceClass;if(r===i){let t=H(e,i);if(!t)throw TypeError(`Unable to find interface with class ${i} that has both IN and OUT endpoints.`);this.controlInterface_=t,this.transferInterface_=t}else{let t=V(e,r);if(!t)throw TypeError(`Unable to find control interface with class ${r}.`);let n=H(e,i)??V(e,i);if(!n)throw TypeError(`Unable to find transfer interface with class ${i}.`);this.controlInterface_=t,this.transferInterface_=n}this.inEndpoint_=U(this.transferInterface_,`in`),this.outEndpoint_=U(this.transferInterface_,`out`)}get readable(){return!this.readable_&&this.device_.opened&&(this.readable_=new ReadableStream(new G(this.device_,this.inEndpoint_,()=>{this.readable_=null}),{highWaterMark:this.serialOptions_?.bufferSize??j})),this.readable_}get writable(){return!this.writable_&&this.device_.opened&&(this.writable_=new WritableStream(new K(this.device_,this.outEndpoint_,()=>{this.writable_=null}),new ByteLengthQueuingStrategy({highWaterMark:this.serialOptions_?.bufferSize??j}))),this.writable_}async open(e){this.serialOptions_=e,this.validateOptions();try{switch(await this.device_.open(),this.device_.configuration===null&&await this.device_.selectConfiguration(1),await this.device_.claimInterface(this.controlInterface_.interfaceNumber),this.controlInterface_!==this.transferInterface_&&await this.device_.claimInterface(this.transferInterface_.interfaceNumber),this.protocol_){case`cdc_acm`:await this.cdcInit();break;case`cp210x`:await this.cp210xInit();break;case`none`:break}}catch(e){throw this.device_.opened&&await this.device_.close(),Error(`Error setting up device: `+(e instanceof Error?e.message:String(e)),{cause:e})}}async close(){let e=[];if(this.readable_&&e.push(this.readable_.cancel()),this.writable_&&e.push(this.writable_.abort()),await Promise.all(e),this.readable_=null,this.writable_=null,this.device_.opened){switch(this.protocol_){case`cdc_acm`:await this.cdcSetSignals({dataTerminalReady:!1,requestToSend:!1});break;case`cp210x`:await this.cp210xDeinit();break}await this.device_.close()}}async forget(){return this.device_.forget()}getInfo(){return{usbVendorId:this.device_.vendorId,usbProductId:this.device_.productId}}async cdcInit(){await this.cdcSetLineCoding(),await this.cdcSetSignals({dataTerminalReady:!0})}async cdcSetSignals(e){if(this.cdcOutputSignals_={...this.cdcOutputSignals_,...e},e.dataTerminalReady!==void 0||e.requestToSend!==void 0){let e=!!this.cdcOutputSignals_.dataTerminalReady|(this.cdcOutputSignals_.requestToSend?2:0);await this.device_.controlTransferOut({requestType:`class`,recipient:`interface`,request:T,value:e,index:this.controlInterface_.interfaceNumber})}}async cdcSetLineCoding(){let e=new ArrayBuffer(7),t=new DataView(e);if(t.setUint32(0,this.serialOptions_.baudRate,!0),t.setUint8(4,z.indexOf(this.serialOptions_.stopBits??P)),t.setUint8(5,R.indexOf(this.serialOptions_.parity??N)),t.setUint8(6,this.serialOptions_.dataBits??M),(await this.device_.controlTransferOut({requestType:`class`,recipient:`interface`,request:w,value:0,index:this.controlInterface_.interfaceNumber},e)).status!==`ok`)throw new DOMException(`Failed to set line coding.`,`NetworkError`)}async cp210xInit(){let e=this.controlInterface_.interfaceNumber;await this.device_.controlTransferOut({requestType:`vendor`,recipient:`interface`,request:E,value:A,index:e});let t=new ArrayBuffer(4);new DataView(t).setUint32(0,this.serialOptions_.baudRate,!0),await this.device_.controlTransferOut({requestType:`vendor`,recipient:`interface`,request:D,value:0,index:e},t);let n=this.serialOptions_.dataBits??M,r={none:0,odd:16,even:32}[this.serialOptions_.parity??N]??0,i=({1:0,2:2}[this.serialOptions_.stopBits??P]??0)<<8|r|n;await this.device_.controlTransferOut({requestType:`vendor`,recipient:`interface`,request:O,value:i,index:e}),await this.device_.controlTransferOut({requestType:`vendor`,recipient:`interface`,request:k,value:re,index:e})}async cp210xDeinit(){let e=this.controlInterface_.interfaceNumber;await this.device_.controlTransferOut({requestType:`vendor`,recipient:`interface`,request:k,value:ie,index:e}),await this.device_.controlTransferOut({requestType:`vendor`,recipient:`interface`,request:E,value:ne,index:e})}validateOptions(){if(this.serialOptions_.baudRate%1!=0)throw RangeError(`Invalid baud rate: ${this.serialOptions_.baudRate}`);if(this.serialOptions_.dataBits!==void 0&&!F.includes(this.serialOptions_.dataBits))throw RangeError(`Invalid dataBits: ${this.serialOptions_.dataBits}`);if(this.serialOptions_.stopBits!==void 0&&!I.includes(this.serialOptions_.stopBits))throw RangeError(`Invalid stopBits: ${this.serialOptions_.stopBits}`);if(this.serialOptions_.parity!==void 0&&!L.includes(this.serialOptions_.parity))throw RangeError(`Invalid parity: ${this.serialOptions_.parity}`)}},J=class{options_;constructor(e){this.options_={...B,...e}}async requestPort(e,t){let n={...this.options_,...t},r=[];if(e?.filters&&e.filters.length>0)for(let t of e.filters){let e={};t.usbVendorId!==void 0&&(e.vendorId=t.usbVendorId),t.usbProductId!==void 0&&(e.productId=t.usbProductId),n.usbControlInterfaceClass!==void 0&&n.usbControlInterfaceClass!==255?e.classCode=n.usbControlInterfaceClass:e.vendorId===void 0&&e.productId===void 0&&(e.classCode=n.usbControlInterfaceClass??2),r.push(e)}else r.push({classCode:n.usbControlInterfaceClass??2});return new q(await navigator.usb.requestDevice({filters:r}),n)}async getPorts(e){let t={...this.options_,...e},n=await navigator.usb.getDevices(),r=[];for(let e of n)try{let n=new q(e,t);r.push(n)}catch{}return r}},Y=`6e400001-b5a3-f393-e0a9-e50e24dcca9e`,ae=`6e400003-b5a3-f393-e0a9-e50e24dcca9e`,oe=`6e400002-b5a3-f393-e0a9-e50e24dcca9e`,X=20,se=10;function ce(e){let t=null,n=null,r=null;return{get readable(){return t},get writable(){return n},getInfo(){return{}},async open(){if(!e.gatt)throw Error(`GATT not available on this Bluetooth device.`);r=await e.gatt.connect();let i=await r.getPrimaryService(Y),a=await i.getCharacteristic(ae),o=await i.getCharacteristic(oe);await a.startNotifications(),t=new ReadableStream({start(e){a.addEventListener(`characteristicvaluechanged`,t=>{let n=t.target.value.buffer;e.enqueue(new Uint8Array(n))})}}),n=new WritableStream({async write(e){for(let t=0;t<e.length;t+=X){let n=e.slice(t,t+X);await o.writeValueWithoutResponse(n),t+X<e.length&&await new Promise(e=>setTimeout(e,se))}}})},async close(){r?.connected&&r.disconnect(),t=null,n=null}}}function le(){return{async requestPort(){if(!navigator.bluetooth)throw Error(`Web Bluetooth API is not supported in this browser. Use Chrome on Android, macOS, or ChromeOS.`);return ce(await navigator.bluetooth.requestDevice({filters:[{services:[Y]}]}))},async getPorts(){return[]}}}function Z(e){return new Promise((t,n)=>{e.addEventListener(`open`,()=>t(),{once:!0}),e.addEventListener(`error`,e=>n(e),{once:!0})})}function Q(e,t){return new Promise(n=>{let r=i=>{let a=JSON.parse(i.data);a.type===t&&(e.removeEventListener(`message`,r),n(a.payload))};e.addEventListener(`message`,r)})}function $(e,t){let n=null,r=null;return{get readable(){return n},get writable(){return r},getInfo(){return{usbVendorId:t.vendorId,usbProductId:t.productId}},async open(i){e.send(JSON.stringify({type:`open`,path:t.path,baudRate:i.baudRate,dataBits:i.dataBits,stopBits:i.stopBits,parity:i.parity,parser:{type:`delimiter`,value:`\\n`}})),await Q(e,`opened`);let a=[],o=null,s=!1;function c(e){let t=JSON.parse(e.data);if(t.type===`data`&&t.bytes){let e=new Uint8Array(t.bytes);o?o.enqueue(e):a.push(e)}t.type===`closed`&&(s=!0,o&&o.close())}e.addEventListener(`message`,c),n=new ReadableStream({start(e){o=e;for(let t of a)e.enqueue(t);a.length=0,s&&e.close()},cancel(){e.removeEventListener(`message`,c),o=null}}),r=new WritableStream({write(t){e.send(JSON.stringify({type:`write`,bytes:Array.from(t)}))}})},async close(){e.send(JSON.stringify({type:`close`})),n=null,r=null,e.close()}}}function ue(e){return{async requestPort(t){let n=new WebSocket(e);await Z(n),n.send(JSON.stringify({type:`list-ports`,filters:t?.filters??[]}));let r=(await Q(n,`port-list`))[0];if(!r)throw Error(`No ports available on the bridge server. Make sure the Node.js server is running and a device is connected.`);return $(n,r)},async getPorts(){let t=new WebSocket(e);return await Z(t),t.send(JSON.stringify({type:`list-ports`,filters:[]})),(await Q(t,`port-list`)).map(e=>$(t,e))}}}exports.AbstractSerialDevice=c,exports.CommandQueue=n,exports.SerialEventEmitter=e,exports.SerialPermissionError=i,exports.SerialPortConflictError=r,exports.SerialReadError=o,exports.SerialRegistry=t,exports.SerialTimeoutError=a,exports.SerialWriteError=s,exports.WebUsbProvider=J,exports.ccTalk=l,exports.createBluetoothProvider=le,exports.createWebSocketProvider=ue,exports.delimiter=f,exports.fixedLength=p,exports.interByteTimeout=m,exports.packetLength=h,exports.raw=g,exports.readline=v,exports.readyParser=b,exports.regexParser=x,exports.slipDecoder=C,exports.slipEncode=ee,exports.spacePacket=te;