UNPKG

@erebus-sh/sdk

Version:
1 lines 64.4 kB
const require_error=require(`./error-BeBbC3SO.cjs`),require_rpc=require(`./rpc-CctEdeqq.cjs`),require_messageBody=require(`./messageBody-BDaUm8G2.cjs`);let consola=require(`consola`);consola=require_error.__toESM(consola);let nanoid=require(`nanoid`);nanoid=require_error.__toESM(nanoid);let zod=require(`zod`);zod=require_error.__toESM(zod);var Authorize=class{client;constructor(p){this.client=require_rpc.createRpcClient(p)}async generateToken(p){try{let I=await this.client.api.erebus.pubsub.grant.$post({json:{channel:p}});if(!I.ok)throw Error(`The auth call failed: ${I.status} ${I.statusText}\nresponse: ${await I.text()}\nPath: ${I.url}`);return(await I.json()).grant_jwt}catch(p){throw Error(`Failed to generate token: ${p instanceof Error?p.message:`Unknown error`}`)}}async healthCheck(){try{return await(await this.client.api[`health-not-meaningful`].$get()).json()}catch(p){throw Error(`Health check failed: ${p instanceof Error?p.message:`Unknown error`}`)}}async generateTestToken(){try{let p=await this.client.api[`generate-token-test`].$get();return p.ok,await p.json()}catch(p){throw Error(`Failed to generate test token: ${p instanceof Error?p.message:`Unknown error`}`)}}};const VERSION=`1`,RequestId=zod.z.string().min(1).optional(),ConnectPacket=zod.z.object({packetType:zod.z.literal(`connect`),version:zod.z.literal(`1`),grantJWT:zod.z.string().min(1)}),SubscribePacket=zod.z.object({packetType:zod.z.literal(`subscribe`),requestId:RequestId,topic:zod.z.string().min(1)}),UnsubscribePacket=zod.z.object({packetType:zod.z.literal(`unsubscribe`),requestId:RequestId,topic:zod.z.string().min(1)}),PresencePacket=zod.z.object({packetType:zod.z.literal(`presence`),clientId:zod.z.string().min(1),topic:zod.z.string().min(1),status:zod.z.enum([`online`,`offline`])}),PublishPacket=zod.z.object({packetType:zod.z.literal(`publish`),ack:zod.z.boolean().optional(),requestId:RequestId,topic:zod.z.string().min(1),payload:require_messageBody.MessageBodySchema,clientMsgId:zod.z.string().min(1)}),BaseAck=zod.z.object({type:zod.z.literal(`ack`),path:zod.z.enum([`publish`,`subscribe`,`unsubscribe`]),seq:zod.z.string().min(1),serverAssignedId:zod.z.string().min(1),clientMsgId:zod.z.string().min(1)}),AckPublishOk=BaseAck.extend({path:zod.z.literal(`publish`),topic:zod.z.string().min(1),result:zod.z.object({ok:zod.z.literal(!0),t_ingress:zod.z.number()})}),AckPublishErr=BaseAck.extend({path:zod.z.literal(`publish`),topic:zod.z.string().min(1),result:zod.z.object({ok:zod.z.literal(!1),code:zod.z.enum([`UNAUTHORIZED`,`FORBIDDEN`,`INVALID`,`RATE_LIMITED`,`INTERNAL`]),message:zod.z.string().min(1)})}),AckSubscription=BaseAck.extend({path:zod.z.enum([`subscribe`,`unsubscribe`]),topic:zod.z.string().min(1),result:zod.z.object({ok:zod.z.literal(!0),status:zod.z.enum([`subscribed`,`unsubscribed`])})}),AckResultSchema=zod.z.discriminatedUnion(`path`,[AckPublishOk,AckPublishErr,AckSubscription]),AckPacket=zod.z.object({packetType:zod.z.literal(`ack`),clientMsgId:RequestId,result:AckResultSchema}),PacketEnvelopeSchema=zod.z.discriminatedUnion(`packetType`,[ConnectPacket,SubscribePacket,UnsubscribePacket,PresencePacket,PublishPacket,AckPacket]);function encodeEnvelope(p){require_messageBody.logger.info(`[encodeEnvelope] called`,{packetType:p.packetType}),require_messageBody.logger.info(`[encodeEnvelope] validating packet`,{packetType:p.packetType}),PacketEnvelopeSchema.parse(p),require_messageBody.logger.info(`[encodeEnvelope] packet validated`,{packetType:p.packetType});let I=JSON.stringify(p);return require_messageBody.logger.info(`[encodeEnvelope] packet encoded`,{packetType:p.packetType,encodedLength:I.length}),I}function parseServerFrame(p){if(require_messageBody.logger.info(`[parseServerFrame] called`,{rawLength:p.length}),!p||typeof p!=`string`||p.trim().length===0)return require_messageBody.logger.warn(`[parseServerFrame] Invalid raw data`,{raw:p}),null;try{require_messageBody.logger.info(`[parseServerFrame] parsing JSON`);let I=JSON.parse(p);if(require_messageBody.logger.info(`[parseServerFrame] JSON parsed`,{keys:Object.keys(I)}),!I||typeof I!=`object`)return require_messageBody.logger.warn(`[parseServerFrame] Parsed data is not an object`,{data:I}),null;if(I.packetType===`ack`){require_messageBody.logger.info(`[parseServerFrame] validating ACK packet schema`);let p=parseAckPacket(I);return p?(require_messageBody.logger.info(`[parseServerFrame] ACK packet validated`,{clientMsgId:I.clientMsgId}),p):(require_messageBody.logger.warn(`[parseServerFrame] ACK packet parsing failed`),null)}else if(I.packetType===`presence`){require_messageBody.logger.info(`[parseServerFrame] validating presence packet schema`);let p=PresencePacket.parse(I);return require_messageBody.logger.info(`[parseServerFrame] presence packet validated`,{topic:p.topic,clientId:p.clientId}),p}else{if(!I.topic||typeof I.topic!=`string`)return require_messageBody.logger.warn(`[parseServerFrame] Missing or invalid topic`,{data:I}),null;require_messageBody.logger.info(`[parseServerFrame] validating message schema`);let p=require_messageBody.MessageBodySchema.parse(I);return require_messageBody.logger.info(`[parseServerFrame] message schema validated`,{topic:p.topic}),{packetType:`publish`,topic:p.topic,payload:p}}}catch(I){return require_messageBody.logger.warn(`[parseServerFrame] failed`,{error:I instanceof Error?I.message:String(I)},p),null}}function parseAckPacket(p){try{if(p.packetType!==`ack`||!p.result||typeof p.result!=`object`)return null;let I=p.result,R=I.path;if(R===`subscribe`||R===`unsubscribe`){let L=AckSubscription.parse(I);return{packetType:`ack`,clientMsgId:p.clientMsgId,result:L}}else if(R===`publish`&&I.result&&typeof I.result==`object`&&`ok`in I.result)if(I.result.ok){let L=AckPublishOk.parse(I);return{packetType:`ack`,clientMsgId:p.clientMsgId,result:L}}else{let L=AckPublishErr.parse(I);return{packetType:`ack`,clientMsgId:p.clientMsgId,result:L}}return require_messageBody.logger.warn(`[parseAckPacket] Unknown ACK type`,{path:R}),null}catch(p){return require_messageBody.logger.warn(`[parseAckPacket] Failed to parse ACK packet`,{error:p}),null}}function parseMessageBody(p){require_messageBody.logger.info(`[parseMessageBody] called (legacy)`,{rawLength:p.length});let I=parseServerFrame(p);return I&&I.packetType===`publish`?I.payload:null}function validateWebSocketUrl(p){if(!p)return!1;try{let I=new URL(p);return!(I.protocol!==`ws:`&&I.protocol!==`wss:`||!I.hostname.includes(`localhost`)&&I.protocol===`ws:`)}catch{return!1}}function backoff(p,I=5e3){let R=250*2**p,z=Math.floor(Math.random()*200),B=Math.min(I,R)+z;return require_messageBody.logger.info(`backoff computed`,{attempt:p,capMs:I,base:R,jitter:z,delay:B}),B}let WsErrors=function(p){return p[p.BadRequest=4400]=`BadRequest`,p[p.Unauthorized=4401]=`Unauthorized`,p[p.Forbidden=4403]=`Forbidden`,p[p.NotFound=4404]=`NotFound`,p[p.MethodNotAllowed=4405]=`MethodNotAllowed`,p[p.NotAcceptable=4406]=`NotAcceptable`,p[p.RequestTimeout=4408]=`RequestTimeout`,p[p.Conflict=4409]=`Conflict`,p[p.PreconditionFailed=4412]=`PreconditionFailed`,p[p.InternalServerError=4500]=`InternalServerError`,p[p.VersionMismatch=4413]=`VersionMismatch`,p}({});var BackpressureError=class extends Error{},NotConnectedError=class extends Error{},ConnectionManager=class{#url;#channel;#ws;#retry=0;#state=`idle`;#connectionId;#grant;#autoReconnect;#onMessage;#log;#debugHexDump;constructor(p){if(this.#connectionId=`conn_${Math.random().toString(36).substring(2,8)}`,require_messageBody.logger.info(`[${this.#connectionId}] ConnectionManager created`,{url:p.url}),!validateWebSocketUrl(p.url))throw require_messageBody.logger.error(`[${this.#connectionId}] Invalid WebSocket URL`,{url:p.url}),Error(`Invalid WebSocket URL`);this.#url=p.url,this.#channel=p.channel,this.#grant=``,this.#onMessage=p.onMessage,this.#log=p.log??(()=>{}),this.#autoReconnect=p.autoReconnect??!1,this.#debugHexDump=p.debugHexDump??!1}get state(){return this.#state}get isConnected(){return this.#state===`open`}get isConnecting(){return this.#state===`connecting`}get isClosed(){return this.#state===`closed`}get isIdle(){return this.#state===`idle`}get connectionId(){return this.#connectionId}get url(){return this.#url}get bufferedAmount(){return this.#ws?.bufferedAmount??0}get readyState(){return this.#ws?.readyState}get channel(){return this.#channel}async open(p){if(require_messageBody.logger.info(`[${this.#connectionId}] Opening connection`,{timeout:p.timeout}),this.#log(`info`,`connection.open called`),this.#state===`connecting`||this.#state===`open`){require_messageBody.logger.info(`[${this.#connectionId}] Connection already ${this.#state}, returning early`);return}if(!this.#channel||this.#channel.trim().length===0){let p=`Channel must be set before opening connection`;throw require_messageBody.logger.error(`[${this.#connectionId}] ${p}`,{channel:this.#channel}),Error(p)}require_messageBody.logger.info(`[${this.#connectionId}] Setting state to connecting`),this.#state=`connecting`,this.#grant=p.grant;let I=await this.#createWebSocket(p.grant);if(this.#ws=I,this.#setupWebSocketListeners(I),p.timeout){require_messageBody.logger.info(`[${this.#connectionId}] Setting connection timeout`,{timeout:p.timeout});let R=setTimeout(()=>{throw require_messageBody.logger.error(`[${this.#connectionId}] Connection timeout reached`,{timeout:p.timeout}),I.close(),Error(`Connection timeout`)},p.timeout);await new Promise(p=>I.addEventListener(`open`,()=>{require_messageBody.logger.info(`[${this.#connectionId}] Connection opened within timeout, clearing timeout`),clearTimeout(R),p()},{once:!0}))}else require_messageBody.logger.info(`[${this.#connectionId}] Waiting for connection to open (no timeout)`),await new Promise(p=>I.addEventListener(`open`,()=>{require_messageBody.logger.info(`[${this.#connectionId}] Connection opened successfully`),p()},{once:!0}))}close(){if(require_messageBody.logger.info(`[${this.#connectionId}] Connection close called (url: ${this.#url})`),this.#log(`info`,`connection close called (url: ${this.#url})`),this.#state=`closed`,require_messageBody.logger.info(`[${this.#connectionId}] Connection state set to closed (url: ${this.#url})`),this.#ws){try{(this.#ws.readyState===WebSocket.OPEN||this.#ws.readyState===WebSocket.CONNECTING)&&this.#ws.close()}catch(p){require_messageBody.logger.warn(`[${this.#connectionId}] Error closing WebSocket`,{error:p})}this.#ws=void 0}require_messageBody.logger.info(`[${this.#connectionId}] Connection closed and cleaned up`)}send(p){if(require_messageBody.logger.info(`[${this.#connectionId}] Sending packet`,{packetType:p.packetType}),!p||typeof p!=`object`){let I=`Invalid packet: must be an object`;throw require_messageBody.logger.error(`[${this.#connectionId}] ${I}`,{pkt:p}),Error(I)}if(!this.#ws||this.#ws.readyState!==WebSocket.OPEN)throw require_messageBody.logger.error(`[${this.#connectionId}] Cannot send packet - WebSocket not ready`,{hasWs:!!this.#ws,readyState:this.#ws?.readyState,state:this.#state}),new NotConnectedError(`Not connected readyState: `+this.#ws?.readyState);let I=this.#ws.bufferedAmount;if(I>1e6)throw require_messageBody.logger.error(`[${this.#connectionId}] Critical backpressure - closing connection`,{buffered:I,limit:1e6}),this.#log(`error`,`critical backpressure; reconnecting`,{buffered:I}),this.#ws.close(),new BackpressureError(`Critical backpressure`);try{let I=encodeEnvelope(p);require_messageBody.logger.info(`[ConnectionManager] [${this.#connectionId}] Packet encoded, sending via WebSocket`,{packetType:p.packetType,encodedLength:I.length}),this.#ws.send(I)}catch(I){throw require_messageBody.logger.error(`[${this.#connectionId}] Error sending packet`,{error:I,packetType:p.packetType}),I}}sendRaw(p){if(require_messageBody.logger.info(`[${this.#connectionId}] Sending raw data`,{dataType:typeof p,dataLength:p.length}),!this.#ws||this.#ws.readyState!==WebSocket.OPEN)throw require_messageBody.logger.error(`[${this.#connectionId}] Cannot send raw data - WebSocket not ready`,{hasWs:!!this.#ws,readyState:this.#ws?.readyState,state:this.#state}),new NotConnectedError(`Not connected readyState: `+this.#ws?.readyState);try{this.#ws.send(p),require_messageBody.logger.info(`[${this.#connectionId}] Raw data sent successfully`)}catch(I){throw require_messageBody.logger.error(`[${this.#connectionId}] Error sending raw data`,{error:I,dataLength:p.length}),I}}setChannel(p){if(require_messageBody.logger.info(`[${this.#connectionId}] Setting channel`,{channel:p}),!p||typeof p!=`string`||p.trim().length===0){let I=`Invalid channel: must be a non-empty string`;throw require_messageBody.logger.error(`[${this.#connectionId}] ${I}`,{channel:p}),Error(I)}this.#channel=p,require_messageBody.logger.info(`[${this.#connectionId}] Channel set successfully`,{channel:this.#channel})}async#createWebSocket(p){let I=new URL(this.#url);I.searchParams.set(`grant`,p),require_messageBody.logger.info(`[${this.#connectionId}] Creating WebSocket connection`,{url:this.#url,grant:p.substring(0,10)+`...`});let R=new WebSocket(I.toString());try{`binaryType`in R&&(R.binaryType=`arraybuffer`)}catch{}return R}#setupWebSocketListeners(I){I.addEventListener(`open`,()=>{require_messageBody.logger.info(`[${this.#connectionId}] WebSocket opened successfully`),this.#retry=0,this.#state=`open`,this.#log(`info`,`ws open`)},{once:!0}),I.addEventListener(`message`,p=>{this.#handleMessage(p)}),I.addEventListener(`close`,I=>{if(this.#log(`warn`,`ws close encountered`,{retry:this.#retry}),require_messageBody.logger.warn(`[${this.#connectionId}] WebSocket close encountered`,{retry:this.#retry,state:this.#state}),I.code===WsErrors.VersionMismatch)throw new require_error.ErebusError(`Version mismatch: ${I.reason} current client version: 1`);this.#state!==`closed`&&this.#autoReconnect?this.#reconnect():this.#state=`closed`}),I.addEventListener(`error`,p=>{this.#log(`warn`,`ws error`,p),require_messageBody.logger.warn(`[${this.#connectionId}] WebSocket error`,{error:p,state:this.#state,readyState:I.readyState,url:this.#url})})}async#handleMessage(p){if(this.#log(`info`,`ws message received`),this.#debugHexDump){let I=this.#getHexDump(p.data)}try{let I=await this.#convertToString(p.data);if(I.length===0){require_messageBody.logger.warn(`[${this.#connectionId}] Data string is empty, skipping`);return}this.#onMessage({rawData:I})}catch(p){require_messageBody.logger.error(`[${this.#connectionId}] Error handling message`,{error:p})}}#getHexDump(p){return typeof p==`string`?Buffer.from(p,`utf8`).toString(`hex`):p instanceof ArrayBuffer?Buffer.from(p).toString(`hex`):typeof p==`object`&&p&&`arrayBuffer`in p?`[blob-data]`:``}async#convertToString(p){if(typeof p==`string`)return p;if(p==null)return require_messageBody.logger.warn(`[${this.#connectionId}] Data is undefined or null, using empty string`),``;if(p&&typeof p==`object`&&`arrayBuffer`in p&&typeof p.arrayBuffer==`function`){let I=await p.arrayBuffer(),L=new Uint8Array(I);return new TextDecoder().decode(L)}else if(typeof Buffer<`u`&&Buffer.isBuffer(p)){let I=p,L=new Uint8Array(I.buffer,I.byteOffset,I.byteLength);return new TextDecoder().decode(L)}else if(p instanceof ArrayBuffer){let I=new Uint8Array(p);return new TextDecoder().decode(I)}else if(p instanceof Uint8Array)return new TextDecoder().decode(p);else return String(p)}#reconnect(){if(this.#state===`closed`||this.#state===`connecting`){require_messageBody.logger.info(`[${this.#connectionId}] Reconnect called but connection is ${this.#state}, ignoring`);return}require_messageBody.logger.info(`[${this.#connectionId}] Starting reconnect process`),this.#state=`idle`;let p=backoff(this.#retry,5e3);this.#log(`info`,`scheduling reconnect`,{retry:this.#retry,bckOff:p}),require_messageBody.logger.info(`[${this.#connectionId}] Scheduling reconnect`,{retry:this.#retry,backoff:p}),this.#retry++,setTimeout(()=>{require_messageBody.logger.info(`[${this.#connectionId}] Executing scheduled reconnect`),this.open({grant:this.#grant,timeout:5e3}).catch(p=>{require_messageBody.logger.error(`[${this.#connectionId}] Reconnect failed`,{error:p}),this.#state=`closed`})},p)}},AckManager=class{#pendingPublishes=new Map;#clientMsgIdToRequestId=new Map;#pendingSubscriptions=new Map;#subscriptionMsgIdToRequestId=new Map;#connectionId;constructor(p){this.#connectionId=p,require_messageBody.logger.info(`[${this.#connectionId}] AckManager created`)}trackPublish(p,I){require_messageBody.logger.info(`[${this.#connectionId}] Tracking publish for ACK`,{requestId:p,clientMsgId:I.clientMsgId,topic:I.topic}),this.#pendingPublishes.set(p,I),this.#clientMsgIdToRequestId.set(I.clientMsgId,p),I.timeoutId&&require_messageBody.logger.info(`[${this.#connectionId}] ACK timeout set`,{requestId:p,timeout:`already configured`})}trackSubscription(p,I){require_messageBody.logger.info(`[${this.#connectionId}] Tracking subscription for ACK`,{requestId:p,clientMsgId:I.clientMsgId,topic:I.topic,path:I.path,clientMsgIdType:typeof I.clientMsgId,clientMsgIdLength:I.clientMsgId?.length}),this.#pendingSubscriptions.set(p,I),I.clientMsgId?(this.#subscriptionMsgIdToRequestId.set(I.clientMsgId,p),require_messageBody.logger.info(`[${this.#connectionId}] Stored clientMsgId mapping`,{clientMsgId:I.clientMsgId,requestId:p,totalMappings:this.#subscriptionMsgIdToRequestId.size})):require_messageBody.logger.info(`[${this.#connectionId}] No clientMsgId provided for subscription tracking`,{requestId:p,note:`ACK matching will rely on other mechanisms`}),I.timeoutId&&require_messageBody.logger.info(`[${this.#connectionId}] Subscription ACK timeout set`,{requestId:p,timeout:`already configured`})}handleAck(p){require_messageBody.logger.info(`[${this.#connectionId}] Handling ACK packet`,{clientMsgId:p.clientMsgId,path:p.result.path}),p.result.path===`publish`?this.#handlePublishAck(p):p.result.path===`subscribe`||p.result.path===`unsubscribe`?this.#handleSubscriptionAck(p):require_messageBody.logger.warn(`[${this.#connectionId}] Unknown ACK path`,{path:p.result.path,clientMsgId:p.clientMsgId})}#handlePublishAck(p){let I=p.clientMsgId;if(!I){require_messageBody.logger.warn(`[${this.#connectionId}] Publish ACK packet missing clientMsgId`);return}let R=this.#clientMsgIdToRequestId.get(I);if(!R){require_messageBody.logger.warn(`[${this.#connectionId}] No requestId found for publish clientMsgId`,{clientMsgId:I});return}let z=this.#pendingPublishes.get(R);if(!z){require_messageBody.logger.warn(`[${this.#connectionId}] No pending publish found for ACK`,{requestId:R,clientMsgId:I});return}z.timeoutId&&clearTimeout(z.timeoutId),this.#pendingPublishes.delete(R),this.#clientMsgIdToRequestId.delete(I);let B=this.#createAckResponse(p,z);require_messageBody.logger.info(`[${this.#connectionId}] Calling publish ACK callback`,{requestId:R,clientMsgId:I,success:B.success});try{z.callback(B)}catch(p){require_messageBody.logger.error(`[${this.#connectionId}] Error in publish ACK callback`,{error:p,requestId:R,clientMsgId:I})}}#handleSubscriptionAck(p){let I=p.clientMsgId,R,z;if(require_messageBody.logger.info(`[${this.#connectionId}] Processing subscription ACK`,{path:p.result.path,topic:p.result.topic,clientMsgId:I,pendingSubscriptionCount:this.#pendingSubscriptions.size,subscriptionMsgIdMappings:Array.from(this.#subscriptionMsgIdToRequestId.entries()).map(([p,I])=>`${p} -> ${I}`)}),I&&(R=this.#subscriptionMsgIdToRequestId.get(I),require_messageBody.logger.info(`[${this.#connectionId}] Looking up clientMsgId in mappings`,{clientMsgId:I,foundRequestId:R}),R?(z=this.#pendingSubscriptions.get(R),require_messageBody.logger.info(`[${this.#connectionId}] Looking up requestId in pending subscriptions`,{requestId:R,foundPending:!!z})):(require_messageBody.logger.info(`[${this.#connectionId}] No direct mapping found, checking if clientMsgId matches a requestId`,{clientMsgId:I}),z=this.#pendingSubscriptions.get(I),z&&(R=I,require_messageBody.logger.info(`[${this.#connectionId}] Found pending subscription by matching clientMsgId to requestId`,{clientMsgId:I,requestId:R})))),!z){require_messageBody.logger.info(`[${this.#connectionId}] Received untracked subscription ACK`,{path:p.result.path,topic:p.result.topic,clientMsgId:I,note:`This is normal for optimistic subscriptions`});return}require_messageBody.logger.info(`[${this.#connectionId}] Handling tracked subscription ACK`,{requestId:R,clientMsgId:I,topic:z.topic,path:z.path}),z.timeoutId&&clearTimeout(z.timeoutId),this.#pendingSubscriptions.delete(R),I&&this.#subscriptionMsgIdToRequestId.delete(I);let B=this.#createSubscriptionResponse(p,z);require_messageBody.logger.info(`[${this.#connectionId}] Calling subscription ACK callback`,{requestId:R,clientMsgId:I,topic:z.topic,success:B.success});try{z.callback(B)}catch(p){require_messageBody.logger.error(`[${this.#connectionId}] Error in subscription ACK callback`,{error:p,requestId:R,clientMsgId:I,topic:z.topic})}}handlePublishTimeout(p){require_messageBody.logger.warn(`[${this.#connectionId}] Publish ACK timeout`,{requestId:p});let I=this.#pendingPublishes.get(p);if(!I)return;this.#pendingPublishes.delete(p),this.#clientMsgIdToRequestId.delete(I.clientMsgId);let R={success:!1,ack:{},error:{code:`TIMEOUT`,message:`Publish ACK not received within timeout`},topic:I.topic};try{I.callback(R)}catch(I){require_messageBody.logger.error(`[${this.#connectionId}] Error in publish timeout callback`,{error:I,requestId:p})}}handleSubscriptionTimeout(p){require_messageBody.logger.warn(`[${this.#connectionId}] Subscription ACK timeout`,{requestId:p});let I=this.#pendingSubscriptions.get(p);if(!I)return;this.#pendingSubscriptions.delete(p),I.clientMsgId&&this.#subscriptionMsgIdToRequestId.delete(I.clientMsgId);let R={success:!1,error:{code:`TIMEOUT`,message:`Subscription ACK not received within timeout`},topic:I.topic,path:I.path};try{I.callback(R)}catch(R){require_messageBody.logger.error(`[${this.#connectionId}] Error in subscription timeout callback`,{error:R,requestId:p,topic:I.topic})}}cleanup(p){require_messageBody.logger.info(`[${this.#connectionId}] Cleaning up pending operations`,{publishCount:this.#pendingPublishes.size,subscriptionCount:this.#pendingSubscriptions.size,reason:p});for(let[I,R]of this.#pendingPublishes){R.timeoutId&&clearTimeout(R.timeoutId);let z={success:!1,ack:{},error:{code:`CONNECTION_ERROR`,message:p},topic:R.topic};try{R.callback(z)}catch(p){require_messageBody.logger.error(`[${this.#connectionId}] Error in publish cleanup callback`,{error:p,requestId:I,clientMsgId:R.clientMsgId})}}for(let[I,R]of this.#pendingSubscriptions){R.timeoutId&&clearTimeout(R.timeoutId);let z={success:!1,error:{code:`CONNECTION_ERROR`,message:p},topic:R.topic,path:R.path};try{R.callback(z)}catch(p){require_messageBody.logger.error(`[${this.#connectionId}] Error in subscription cleanup callback`,{error:p,requestId:I,clientMsgId:R.clientMsgId,topic:R.topic})}}this.#pendingPublishes.clear(),this.#clientMsgIdToRequestId.clear(),this.#pendingSubscriptions.clear(),this.#subscriptionMsgIdToRequestId.clear()}getPendingCount(){return this.#pendingPublishes.size}getPendingSubscriptionCount(){return this.#pendingSubscriptions.size}#createAckResponse(p,I){return p.result.path===`publish`?`result`in p.result&&p.result.result.ok?{success:!0,ack:p,seq:p.result.seq,serverMsgId:p.result.serverAssignedId,topic:p.result.topic}:`result`in p.result&&!p.result.result.ok?{success:!1,ack:p,error:{code:p.result.result.code,message:p.result.result.message},topic:p.result.topic}:{success:!1,ack:p,error:{code:`MALFORMED_ACK`,message:`ACK packet has invalid structure`},topic:I.topic}:(require_messageBody.logger.info(`[${this.#connectionId}] Received non-publish ACK`,{path:p.result.path,clientMsgId:p.clientMsgId,note:`Subscription ACKs are not tracked in AckManager`}),{success:!1,ack:p,error:{code:`INVALID_ACK_TYPE`,message:`Received non-publish ACK for publish operation`},topic:I.topic})}#createSubscriptionResponse(p,I){if(p.result.path===`subscribe`||p.result.path===`unsubscribe`)if(`result`in p.result){let I=p.result.result;if(I.ok)return{success:!0,ack:p,topic:p.result.topic,status:I.status,path:p.result.path};{let L=I;return{success:!1,ack:p,error:{code:L.code||`SUBSCRIPTION_ERROR`,message:L.message||`Subscription operation failed`},topic:p.result.topic,path:p.result.path}}}else return{success:!1,ack:p,error:{code:`MALFORMED_ACK`,message:`Subscription ACK packet has invalid structure`},topic:I.topic,path:I.path};else return{success:!1,ack:p,error:{code:`INVALID_ACK_TYPE`,message:`Received non-subscription ACK for subscription operation`},topic:I.topic,path:I.path}}},SubscriptionManager=class{#subs=new Set;#subscribedTopics=new Set;#unsubscribedTopics=new Set;#connectionId;constructor(p){this.#connectionId=p,require_messageBody.logger.info(`[${this.#connectionId}] SubscriptionManager created`)}get subscriptions(){return Array.from(this.#subs)}get subscribedTopics(){return Array.from(this.#subscribedTopics).filter(p=>!this.#unsubscribedTopics.has(p))}get unsubscribedTopics(){return Array.from(this.#unsubscribedTopics)}get subscriptionCount(){return this.#subs.size}subscribe(p){if(require_messageBody.logger.info(`[${this.#connectionId}] Subscribe to topic`,{topic:p}),!p||typeof p!=`string`||p.trim().length===0){let I=`Invalid topic: must be a non-empty string`;throw require_messageBody.logger.error(`[${this.#connectionId}] ${I}`,{topic:p}),Error(I)}return this.#subscribedTopics.add(p),this.#unsubscribedTopics.delete(p),this.#subs.has(p)?(require_messageBody.logger.info(`[${this.#connectionId}] Topic already subscribed`,{topic:p}),!1):(this.#subs.add(p),require_messageBody.logger.info(`[${this.#connectionId}] Topic added to subscriptions`,{topic:p,totalSubs:this.#subs.size}),!0)}unsubscribe(p){if(require_messageBody.logger.info(`[${this.#connectionId}] Unsubscribe from topic`,{topic:p}),!p||typeof p!=`string`||p.trim().length===0){let I=`Invalid topic: must be a non-empty string`;throw require_messageBody.logger.error(`[${this.#connectionId}] ${I}`,{topic:p}),Error(I)}return this.#subs.has(p)?(this.#unsubscribedTopics.add(p),this.#subscribedTopics.delete(p),this.#subs.delete(p),require_messageBody.logger.info(`[${this.#connectionId}] Topic removed from subscriptions`,{topic:p,totalSubs:this.#subs.size}),!0):(require_messageBody.logger.info(`[${this.#connectionId}] Topic already unsubscribed`,{topic:p}),!1)}isSubscribed(p){return this.#subscribedTopics.has(p)&&!this.#unsubscribedTopics.has(p)}getSubscriptionStatus(p){return this.#subscribedTopics.has(p)&&!this.#unsubscribedTopics.has(p)?`subscribed`:this.#unsubscribedTopics.has(p)?`unsubscribed`:`pending`}clear(){require_messageBody.logger.info(`[${this.#connectionId}] Clearing all subscriptions`),this.#subs.clear(),this.#subscribedTopics.clear(),this.#unsubscribedTopics.clear()}getSubscriptionTracking(){let p=Array.from(this.#subs).filter(p=>!this.#subscribedTopics.has(p)&&!this.#unsubscribedTopics.has(p));return{subscribed:this.subscribedTopics,unsubscribed:this.unsubscribedTopics,pending:p}}getTopicsForResubscription(){return Array.from(this.#subs)}confirmSubscription(p){require_messageBody.logger.info(`[${this.#connectionId}] Confirming subscription`,{topic:p}),this.#subscribedTopics.add(p),this.#unsubscribedTopics.delete(p)}confirmUnsubscription(p){require_messageBody.logger.info(`[${this.#connectionId}] Confirming unsubscription`,{topic:p}),this.#unsubscribedTopics.add(p),this.#subscribedTopics.delete(p),this.#subs.delete(p)}},MessageProcessor=class{#connectionId;#onMessage;#ackManager;#presenceManager;constructor(p,I,R,z){this.#connectionId=p,this.#onMessage=I,this.#ackManager=R,this.#presenceManager=z,require_messageBody.logger.info(`[${this.#connectionId}] MessageProcessor created`)}async processMessage(p){if(require_messageBody.logger.info(`[${this.#connectionId}] Processing message`,{dataLength:p.length}),p.length===0)return require_messageBody.logger.warn(`[${this.#connectionId}] Data string is empty, skipping`),null;if(p===`ping`)return require_messageBody.logger.warn(`[${this.#connectionId}] Ping packet, skipping`,{rawDataPreview:p.slice(0,200)}),null;let I=parseServerFrame(p);return I?(require_messageBody.logger.info(`[${this.#connectionId}] Parsed packet`,{packetType:I.packetType}),await this.handlePacket(I),I):(require_messageBody.logger.warn(`[${this.#connectionId}] Failed to parse server frame`,{rawDataPreview:p.slice(0,200)}),null)}async handlePacket(p){try{p.packetType===`ack`?await this.#handleAckPacket(p):p.packetType===`publish`?(require_messageBody.logger.info(`[${this.#connectionId}] Handling publish message`,{topic:p.payload?.topic,messageId:p.payload?.id||`unknown`}),this.#onMessage(p)):p.packetType===`presence`?(require_messageBody.logger.info(`[${this.#connectionId}] Handling presence packet`,{topic:p.topic,clientId:p.clientId,status:p.status}),this.#presenceManager.handlePresencePacket(p)):require_messageBody.logger.warn(`[${this.#connectionId}] Unknown packet type`,{packetType:p.packetType})}catch(I){require_messageBody.logger.error(`[${this.#connectionId}] Error handling packet`,{error:I,packetType:p.packetType})}}async#handleAckPacket(p){require_messageBody.logger.info(`[${this.#connectionId}] Processing ACK packet`,{clientMsgId:p.clientMsgId,path:p.result.path}),this.#ackManager.handleAck(p)}};const GRANT_CACHE_KEY=`erebus:grant`;function logSensitiveData(p,I=`data`){return!p||p.length<8?`${I}: [too short]`:`${I}: ${p.substring(0,4)}...${p.substring(p.length-4)}`}var GrantManager=class{#connectionId;#tokenProvider;constructor(p,I){this.#connectionId=p,this.#tokenProvider=I,require_messageBody.logger.info(`[${this.#connectionId}] GrantManager created`)}getCachedGrant(){require_messageBody.logger.info(`[${this.#connectionId}] Attempting to get cached grant`);try{if(typeof localStorage<`u`){let p=localStorage.getItem(GRANT_CACHE_KEY);return p?require_messageBody.logger.info(`[${this.#connectionId}] Cached grant found`,{grantPreview:logSensitiveData(p,`cached_grant`)}):require_messageBody.logger.info(`[${this.#connectionId}] No cached grant found`),p??void 0}else require_messageBody.logger.info(`[${this.#connectionId}] localStorage not available (non-browser environment)`)}catch(p){require_messageBody.logger.warn(`[${this.#connectionId}] Error accessing cached grant`,{error:p})}}setCachedGrant(p){require_messageBody.logger.info(`[${this.#connectionId}] Setting cached grant`,{grantPreview:logSensitiveData(p,`grant_to_cache`)});try{typeof localStorage<`u`?(localStorage.setItem(GRANT_CACHE_KEY,p),require_messageBody.logger.info(`[${this.#connectionId}] Grant cached successfully`)):require_messageBody.logger.info(`[${this.#connectionId}] Cannot cache grant - localStorage not available`)}catch(p){require_messageBody.logger.warn(`[${this.#connectionId}] Error caching grant`,{error:p})}}clearCachedGrant(){require_messageBody.logger.info(`[${this.#connectionId}] Clearing cached grant`);try{typeof localStorage<`u`?(localStorage.removeItem(GRANT_CACHE_KEY),require_messageBody.logger.info(`[${this.#connectionId}] Cached grant cleared successfully`)):require_messageBody.logger.info(`[${this.#connectionId}] Cannot clear grant - localStorage not available`)}catch(p){require_messageBody.logger.warn(`[${this.#connectionId}] Error clearing cached grant`,{error:p})}}async getToken(p){require_messageBody.logger.info(`[${this.#connectionId}] Getting token from provider`,{channel:p});try{let I=await this.#tokenProvider(p);if(!I)throw require_messageBody.logger.error(`[${this.#connectionId}] No token provided by token provider`),Error(`No token provided`);return require_messageBody.logger.info(`[${this.#connectionId}] Token received`,{tokenPreview:logSensitiveData(I,`token`),channel:p}),I}catch(I){throw require_messageBody.logger.error(`[${this.#connectionId}] Error getting token from provider`,{error:I,channel:p}),I}}async getTokenWithCache(p){require_messageBody.logger.info(`[${this.#connectionId}] Requesting token from provider`,{channel:p});let I=await this.getToken(p);return I&&(require_messageBody.logger.info(`[${this.#connectionId}] Token received from provider`),this.setCachedGrant(I)),I}},HeartbeatManager=class{#connectionId;#intervalMs;#intervalId;#sendHeartbeat;#log;constructor(p,I,R,z){this.#connectionId=p,this.#intervalMs=I,this.#sendHeartbeat=R,this.#log=z,require_messageBody.logger.info(`[${this.#connectionId}] HeartbeatManager created`,{intervalMs:I})}get isRunning(){return this.#intervalId!==void 0}start(){require_messageBody.logger.info(`[${this.#connectionId}] Starting heartbeat`,{intervalMs:this.#intervalMs}),this.stop(),this.#intervalId=setInterval(()=>{try{this.#log(`info`,`sending heartbeat ping`),require_messageBody.logger.info(`[${this.#connectionId}] Sending heartbeat ping`),this.#sendHeartbeat()}catch(p){throw require_messageBody.logger.error(`[${this.#connectionId}] Error sending heartbeat`,{error:p}),p}},this.#intervalMs),require_messageBody.logger.info(`[${this.#connectionId}] Heartbeat started successfully`)}stop(){this.#intervalId?(require_messageBody.logger.info(`[${this.#connectionId}] Stopping heartbeat`),clearInterval(this.#intervalId),this.#intervalId=void 0):require_messageBody.logger.debug(`[${this.#connectionId}] No heartbeat to stop`)}setInterval(p){require_messageBody.logger.info(`[${this.#connectionId}] Updating heartbeat interval`,{oldInterval:this.#intervalMs,newInterval:p});let I=this.isRunning;this.stop(),this.#intervalMs=p,I&&this.start()}getInterval(){return this.#intervalMs}},PresenceManager=class{#connectionId;#presenceHandlers=new Map;constructor(p){this.#connectionId=p,require_messageBody.logger.info(`[${this.#connectionId}] PresenceManager created`)}onPresence(p,I){if(require_messageBody.logger.info(`[${this.#connectionId}] Adding presence handler for topic`,{topic:p}),!p||typeof p!=`string`||p.trim().length===0){let I=`Invalid topic: must be a non-empty string`;throw require_messageBody.logger.error(`[${this.#connectionId}] ${I}`,{topic:p}),Error(I)}if(typeof I!=`function`){let p=`Invalid handler: must be a function`;throw require_messageBody.logger.error(`[${this.#connectionId}] ${p}`),Error(p)}this.#presenceHandlers.has(p)||this.#presenceHandlers.set(p,new Set),this.#presenceHandlers.get(p).add(I),require_messageBody.logger.info(`[${this.#connectionId}] Presence handler added`,{topic:p,totalHandlers:this.#presenceHandlers.get(p).size})}offPresence(p,I){require_messageBody.logger.info(`[${this.#connectionId}] Removing presence handler for topic`,{topic:p});let R=this.#presenceHandlers.get(p);if(!R){require_messageBody.logger.warn(`[${this.#connectionId}] No handlers found for topic`,{topic:p});return}R.delete(I),R.size===0&&this.#presenceHandlers.delete(p),require_messageBody.logger.info(`[${this.#connectionId}] Presence handler removed`,{topic:p,remainingHandlers:R.size})}clearPresenceHandlers(p){require_messageBody.logger.info(`[${this.#connectionId}] Clearing all presence handlers for topic`,{topic:p}),this.#presenceHandlers.delete(p)}clearAllPresenceHandlers(){require_messageBody.logger.info(`[${this.#connectionId}] Clearing all presence handlers`),this.#presenceHandlers.clear()}handlePresencePacket(p){require_messageBody.logger.info(`[${this.#connectionId}] Handling presence packet`,{clientId:p.clientId,topic:p.topic,status:p.status});let I=this.#presenceHandlers.get(p.topic);if(!I||I.size===0){require_messageBody.logger.debug(`[${this.#connectionId}] No presence handlers found for topic`,{topic:p.topic});return}let R={clientId:p.clientId,topic:p.topic,status:p.status,timestamp:Date.now(),...p.subscribers&&{subscribers:p.subscribers}};for(let z of I)try{z(R)}catch(I){require_messageBody.logger.error(`[${this.#connectionId}] Error in presence handler`,{error:I,topic:p.topic,clientId:p.clientId})}require_messageBody.logger.info(`[${this.#connectionId}] Presence packet handled successfully`,{topic:p.topic,handlersCount:I.size})}getTopicsWithPresenceHandlers(){return Array.from(this.#presenceHandlers.keys())}getPresenceHandlerCount(p){return this.#presenceHandlers.get(p)?.size||0}getTotalPresenceHandlerCount(){let p=0;for(let I of this.#presenceHandlers.values())p+=I.size;return p}get __debugPresenceHandlers(){return new Map(this.#presenceHandlers)}},PubSubConnection=class{#connectionManager;#ackManager;#subscriptionManager;#messageProcessor;#grantManager;#heartbeatManager;#presenceManager;#ackTimeoutMs=3e4;#connectionId;constructor(p){this.#connectionId=`conn_${Math.random().toString(36).slice(2,8)}`,require_messageBody.logger.info(`[${this.#connectionId}] PubSubConnection constructor called`,{url:p.url,heartbeatMs:p.heartbeatMs??25e3}),this.#ackManager=new AckManager(this.#connectionId),this.#subscriptionManager=new SubscriptionManager(this.#connectionId),this.#presenceManager=new PresenceManager(this.#connectionId),this.#grantManager=new GrantManager(this.#connectionId,p.tokenProvider),this.#messageProcessor=new MessageProcessor(this.#connectionId,p.onMessage,this.#ackManager,this.#presenceManager);let I={...p,onMessage:async p=>{p.rawData?await this.#messageProcessor.processMessage(p.rawData):await this.#messageProcessor.handlePacket(p)}};this.#connectionManager=new ConnectionManager(I),this.#heartbeatManager=new HeartbeatManager(this.#connectionId,p.heartbeatMs??25e3,()=>this.#sendHeartbeat(),p.log??(()=>{})),require_messageBody.logger.info(`[${this.#connectionId}] PubSubConnection initialized`)}get state(){return this.#connectionManager.state}get isConnected(){return this.#connectionManager.isConnected}get isConnecting(){return this.#connectionManager.isConnecting}get isClosed(){return this.#connectionManager.isClosed}get isIdle(){return this.#connectionManager.isIdle}get isReadable(){return this.#connectionManager.isConnected}get isWritable(){return this.#connectionManager.isConnected}get channel(){return this.#connectionManager.channel}get subscriptionCount(){return this.#subscriptionManager.subscriptionCount}get subscriptions(){return this.#subscriptionManager.subscriptions}get readyState(){return this.#connectionManager.readyState}get bufferedAmount(){return this.#connectionManager.bufferedAmount}get connectionId(){return this.#connectionManager.connectionId}get url(){return this.#connectionManager.url}get connectionHealth(){return{state:this.state,isConnected:this.isConnected,isReadable:this.isReadable,isWritable:this.isWritable,channel:this.channel,subscriptionCount:this.subscriptionCount,readyState:this.readyState,bufferedAmount:this.bufferedAmount,connectionId:this.connectionId,url:this.url}}get subscribedTopics(){return this.#subscriptionManager.subscribedTopics}get unsubscribedTopics(){return this.#subscriptionManager.unsubscribedTopics}get subscriptionTracking(){return this.#subscriptionManager.getSubscriptionTracking()}async open(p){let I=await this.#grantManager.getTokenWithCache(this.channel);await this.#connectionManager.open({grant:I,timeout:p}),this.#connectionManager.send({packetType:`connect`,version:`1`,grantJWT:I}),this.#heartbeatManager.start();let R=this.#subscriptionManager.getTopicsForResubscription();for(let p of R)require_messageBody.logger.info(`[${this.#connectionId}] Resubscribing to topic`,{topic:p}),this.#connectionManager.send({packetType:`subscribe`,topic:p})}close(){this.#heartbeatManager.stop(),this.#ackManager.cleanup(`Connection closed`),this.#connectionManager.close(),this.#subscriptionManager.clear(),this.#grantManager.clearCachedGrant()}subscribe(p){this.subscribeWithCallback(p)}subscribeWithCallback(p,I,R){if(require_messageBody.logger.info(`[${this.#connectionId}] Subscribe called`,{topic:p,hasCallback:!!I,timeout:R}),!this.#subscriptionManager.subscribe(p)){require_messageBody.logger.info(`[${this.#connectionId}] Topic already subscribed`,{topic:p});return}if(this.isConnected){require_messageBody.logger.info(`[${this.#connectionId}] Connection open, sending subscribe packet`,{topic:p});try{let L,z;if(I){L=`sub_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,typeof crypto<`u`&&typeof crypto.randomUUID==`function`&&(z=crypto.randomUUID());let B={requestId:L,clientMsgId:z,topic:p,path:`subscribe`,callback:I,timestamp:Date.now()};R&&R>0&&(B.timeoutId=setTimeout(()=>{this.#ackManager.handleSubscriptionTimeout(L)},R)),this.#ackManager.trackSubscription(L,B)}this.#connectionManager.send({packetType:`subscribe`,topic:p,...L&&{requestId:L},...z&&{clientMsgId:z}})}catch(I){throw require_messageBody.logger.error(`[${this.#connectionId}] Error sending subscribe packet`,{error:I,topic:p}),this.#subscriptionManager.unsubscribe(p),I}}else require_messageBody.logger.info(`[${this.#connectionId}] Connection not open, subscription will be sent when connected`,{topic:p})}unsubscribe(p){this.unsubscribeWithCallback(p)}unsubscribeWithCallback(p,I,R){if(require_messageBody.logger.info(`[${this.#connectionId}] Unsubscribe called`,{topic:p,hasCallback:!!I,timeout:R}),!this.#subscriptionManager.unsubscribe(p)){require_messageBody.logger.info(`[${this.#connectionId}] Topic already unsubscribed`,{topic:p});return}if(this.isConnected){require_messageBody.logger.info(`[${this.#connectionId}] Connection open, sending unsubscribe packet`,{topic:p});try{let L,z;if(I){L=`unsub_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,typeof crypto<`u`&&typeof crypto.randomUUID==`function`&&(z=crypto.randomUUID());let B={requestId:L,clientMsgId:z,topic:p,path:`unsubscribe`,callback:I,timestamp:Date.now()};R&&R>0&&(B.timeoutId=setTimeout(()=>{this.#ackManager.handleSubscriptionTimeout(L)},R)),this.#ackManager.trackSubscription(L,B)}this.#connectionManager.send({packetType:`unsubscribe`,topic:p,...L&&{requestId:L},...z&&{clientMsgId:z}})}catch(I){require_messageBody.logger.error(`[${this.#connectionId}] Error sending unsubscribe packet`,{error:I,topic:p})}}else require_messageBody.logger.info(`[${this.#connectionId}] Connection not open, unsubscription will be sent when connected`,{topic:p})}publish(p){this.#publishInternal(p,!1)}publishWithAck(p,I,L=this.#ackTimeoutMs){return this.#publishInternal(p,!0,I,L)}isSubscribed(p){return this.#subscriptionManager.isSubscribed(p)}getSubscriptionStatus(p){return this.#subscriptionManager.getSubscriptionStatus(p)}setChannel(p){this.#connectionManager.setChannel(p),this.#grantManager.clearCachedGrant()}onPresence(p,I){this.#presenceManager.onPresence(p,I)}offPresence(p,I){this.#presenceManager.offPresence(p,I)}clearPresenceHandlers(p){this.#presenceManager.clearPresenceHandlers(p)}#publishInternal(p,I=!1,B,V){if(require_messageBody.logger.info(`[${this.#connectionId}] Publish called`,{topic:p.topic,withAck:I}),!p||typeof p!=`object`){let I=`Invalid payload: must be an object`;throw require_messageBody.logger.error(`[${this.#connectionId}] ${I}`,{payload:p}),Error(I)}if(I&&!B){let p=`ACK callback is required when withAck is true`;throw require_messageBody.logger.error(`[${this.#connectionId}] ${p}`),Error(p)}if(!this.isConnected)throw require_messageBody.logger.error(`[${this.#connectionId}] Cannot publish - not connected`,{state:this.state}),new NotConnectedError(`Not connected`);let H=`fallback_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,U;try{if(p.clientPublishTs||Object.assign(p,{clientPublishTs:Date.now()}),p.clientMsgId?H=p.clientMsgId:(H=typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID():`msg_${Date.now()}_${Math.random().toString(36).slice(2,9)}`,Object.assign(p,{clientMsgId:H})),I&&B){U=`req_${Date.now()}_${(0,nanoid.nanoid)()}`;let I={requestId:U,clientMsgId:H,topic:p.topic,callback:B,timestamp:Date.now()};V&&V>0&&(I.timeoutId=setTimeout(()=>{this.#ackManager.handlePublishTimeout(U)},V)),this.#ackManager.trackPublish(U,I)}}catch(I){Object.assign(p,{clientMsgId:H}),require_messageBody.logger.warn(`[${this.#connectionId}] Error setting client fields, using fallback`,{err:I,clientMsgId:H})}require_messageBody.logger.info(`[${this.#connectionId}] Publishing message`,{topic:p.topic,withAck:I,requestId:U,clientMsgId:H}),consola.default.info(`[PubSubConnection] [${this.#connectionId}] Publishing message`,{topic:p.topic,withAck:I});try{this.#connectionManager.send({packetType:`publish`,topic:p.topic,ack:I,payload:p,clientMsgId:H,...I&&U&&{requestId:U}})}catch(R){throw I&&U&&this.#ackManager.getPendingCount(),require_messageBody.logger.error(`[${this.#connectionId}] Error publishing message`,{error:R,topic:p.topic}),R}return Promise.resolve(H)}#sendHeartbeat(){if(!this.isConnected){require_messageBody.logger.debug(`[${this.#connectionId}] Skipping heartbeat - not connected`);return}try{this.#connectionManager.sendRaw(`ping`)}catch(p){throw require_messageBody.logger.error(`[${this.#connectionId}] Error sending heartbeat`,{error:p}),this.#connectionManager.close(),p}}get __debugObject(){return{connectionManager:this.#connectionManager,ackManager:this.#ackManager,subscriptionManager:this.#subscriptionManager,messageProcessor:this.#messageProcessor,grantManager:this.#grantManager,heartbeatManager:this.#heartbeatManager}}get __debugState(){return this.#connectionManager.state}},StateManager=class{#connectionId;#connectionState=`idle`;#channel=null;#subscriptions=new Map;#processedMessages=new Set;#pendingSubscriptions=new Set;#handlers=new Map;#lastActivity=Date.now();#error=null;#isReconnecting=!1;#reconnectAttempts=0;constructor(p){this.#connectionId=p,require_messageBody.logger.info(`[${this.#connectionId}] StateManager created`)}get connectionState(){return this.#connectionState}setConnectionState(p){require_messageBody.logger.info(`[${this.#connectionId}] Connection state changed`,{from:this.#connectionState,to:p}),this.#connectionState=p,this.#updateActivity()}get isConnected(){return this.#connectionState===`open`}get isConnecting(){return this.#connectionState===`connecting`}get isClosed(){return this.#connectionState===`closed`}get isIdle(){return this.#connectionState===`idle`}get channel(){return this.#channel}setChannel(p){require_messageBody.logger.info(`[${this.#connectionId}] Channel set`,{channel:p}),this.#channel=p,this.#updateActivity()}getChannel(){return this.#channel}get subscriptionCount(){return this.#subscriptions.size}get activeTopics(){return Array.from(this.#subscriptions.entries()).filter(([p,I])=>I===`subscribed`).map(([p,I])=>p)}get pendingTopics(){return Array.from(this.#subscriptions.entries()).filter(([p,I])=>I===`pending`).map(([p,I])=>p)}get unsubscribedTopics(){return Array.from(this.#subscriptions.entries()).filter(([p,I])=>I===`unsubscribed`).map(([p,I])=>p)}setSubscriptionStatus(p,I){require_messageBody.logger.info(`[${this.#connectionId}] Subscription status updated`,{topic:p,status:I}),this.#subscriptions.set(p,I),this.#updateActivity(),I===`subscribed`?this.#pendingSubscriptions.delete(p):I===`pending`&&this.#pendingSubscriptions.add(p)}getSubscriptionStatus(p){return this.#subscriptions.get(p)||`unsubscribed`}isSubscribed(p){return this.getSubscriptionStatus(p)===`subscribed`}get processedMessagesCount(){return this.#processedMessages.size}addProcessedMessage(p){if(this.#processedMessages.add(p),this.#updateActivity(),this.#processedMessages.size>1e3){let p=Array.from(this.#processedMessages);this.#processedMessages.clear(),p.slice(-500).forEach(p=>this.#processedMessages.add(p))}}isMessageProcessed(p){return this.#processedMessages.has(p)}clearProcessedMessages(){require_messageBody.logger.info(`[${this.#connectionId}] Clearing processed messages`),this.#processedMessages.clear()}get handlerCount(){let p=0;for(let I of this.#handlers.values())p+=I.size;return p}getTopicsWithHandlers(){return Array.from(this.#handlers.keys())}getHandlerCountForTopic(p){return this.#handlers.get(p)?.size||0}addHandler(p,I){this.#handlers.has(p)||this.#handlers.set(p,new Set),this.#handlers.get(p).add(I),this.#updateActivity()}removeHandler(p,I){let L=this.#handlers.get(p);L&&(L.delete(I),L.size===0&&this.#handlers.delete(p)),this.#updateActivity()}clearHandlers(p){this.#handlers.delete(p),this.#updateActivity()}getHandlers(p){return this.#handlers.get(p)}get pendingSubscriptionsCount(){return this.#pendingSubscriptions.size}addPendingSubscription(p){this.#pendingSubscriptions.add(p),this.#updateActivity()}removePendingSubscription(p){this.#pendingSubscriptions.delete(p),this.#updateActivity()}clearPendingSubscriptions(){require_messageBody.logger.info(`[${this.#connectionId}] Clearing pending subscriptions`),this.#pendingSubscriptions.clear()}get hasError(){return this.#error!==null}get error(){return this.#error}setError(p){require_messageBody.logger.error(`[${this.#connectionId}] Error set`,{error:p}),this.#error=p,this.#updateActivity()}clearError(){require_messageBody.logger.info(`[${this.#connectionId}] Error cleared`),this.#error=null,this.#updateActivity()}get isReconnecting(){return this.#isReconnecting}setReconnecting(p){this.#isReconnecting=p,this.#updateActivity()}get reconnectAttempts(){return this.#reconnectAttempts}incrementReconnectAttempts(){this.#reconnectAttempts++,this.#updateActivity()}resetReconnectAttempts(){this.#reconnectAttempts=0,this.#updateActivity()}get lastActivity(){return this.#lastActivity}#updateActivity(){this.#lastActivity=Date.now()}get stateSummary(){return{connectionState:this.#connectionState,channel:this.#channel,subscriptionCount:this.subscriptionCount,handlerCount:this.handlerCount,processedMessagesCount:this.processedMessagesCount,pendingSubscriptionsCount:this.pendingSubscriptionsCount,hasError:this.hasError,isReconnecting:this.#isReconnecting,reconnectAttempts:this.#reconnectAttempts,lastActivity:this.#lastActivity}}reset(){require_messageBody.logger.info(`[${this.#connectionId}] Resetting state manager`),this.#connectionState=`idle`,this.#channel=null,this.#subscriptions.clear(),this.#processedMessages.clear(),this.#pendingSubscriptions.clear(),this.#handlers.clear(),this.#error=null,this.#isReconnecting=!1,this.#reconnectAttempts=0,this.#updateActivity()}clear(){require_messageBody.logger.info(`[${this.#connectionId}] Clearing state manager`),this.#subscriptions.clear(),this.#processedMessages.clear(),this.#pendingSubscriptions.clear(),this.#handlers.clear(),th