UNPKG

porter-source

Version:

Messaging Library for Web Extensions

3 lines (2 loc) 24.6 kB
"use strict";var X=Object.create;var P=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var Y=(s,e)=>{for(var t in e)P(s,t,{get:e[t],enumerable:!0})},$=(s,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of K(e))!Z.call(s,o)&&o!==t&&P(s,o,{get:()=>e[o],enumerable:!(n=J(e,o))||n.enumerable});return s};var D=(s,e,t)=>(t=s!=null?X(j(s)):{},$(e||!s||!s.__esModule?P(t,"default",{value:s,enumerable:!0}):t,s)),ee=s=>$(P({},"__esModule",{value:!0}),s);var oe={};Y(oe,{usePorter:()=>k});module.exports=ee(oe);var h=require("react");var z=D(require("webextension-polyfill"));var L=(a=>(a.ContentScript="contentscript",a.Extension="extension",a.Popup="popup",a.Sidepanel="sidepanel",a.Devtools="devtools",a.Options="options",a.Unknown="unknown",a))(L||{});var g=class extends Error{constructor(t,n,o){super(n);this.type=t;this.details=o;this.name="PorterError"}};function Q(){return typeof ServiceWorkerGlobalScope<"u"&&self instanceof ServiceWorkerGlobalScope}var l=class l{constructor(e){this.context=e}static getLevel(){var t,n;return((t=l.globalOptions)==null?void 0:t.level)!==void 0?l.globalOptions.level:typeof process<"u"&&((n=process.env)==null?void 0:n.PORTER_ENV)==="production"?1:4}static configure(e){l.globalOptions=e,e.level!==void 0&&(l.level=e.level),e.enabled!==void 0&&(l.enabled=e.enabled)}static getLogger(e){return this.instances.has(e)||this.instances.set(e,new l(e)),this.instances.get(e)}error(e,...t){l.enabled&&l.level>=0&&console.error(`[Porter:${this.context}] ${e}`,...t)}warn(e,...t){l.enabled&&l.level>=1&&console.warn(`[Porter:${this.context}] ${e}`,...t)}info(e,...t){l.enabled&&l.level>=2&&console.info(`[Porter:${this.context}] ${e}`,...t)}debug(e,...t){l.enabled&&l.level>=3&&console.debug(`[Porter:${this.context}] ${e}`,...t)}trace(e,...t){l.enabled&&l.level>=4&&console.trace(`[Porter:${this.context}] ${e}`,...t)}};l.level=l.getLevel(),l.enabled=!1,l.instances=new Map;var f=l;var F=D(require("webextension-polyfill")),H=require("uuid");var E=class{constructor(e){this.logger=e;this.agents=new Map;this.agentsInfo=new Map;this.eventHandlers=new Map;this.eventHandlers.set("agentSetup",new Set),this.eventHandlers.set("agentMessage",new Set),this.eventHandlers.set("agentDisconnect",new Set)}addAgent(e,t){var b,y;this.logger.debug("Adding agent",{context:t,port:e});let n=this.identifyConnectionSource(e);if(!n){this.logger.error("Cannot add agent that did not have a sender");return}let o=n.context,r=n.tabId||-1,i=n.frameId||0;this.logger.debug("Determined context for new agent",{determinedContext:o,tabId:r,frameId:i});let a=Array.from(this.agentsInfo.values()).filter(d=>d.location.context===o&&d.location.tabId===r&&d.location.frameId===i);a.length>0&&this.logger.debug("Adding agent: Found existing similar agent.",{tabAgentsInfo:a});let u=((y=(b=this.getAgentByLocation({context:o,tabId:r,frameId:i}))==null?void 0:b.info)==null?void 0:y.id)||(0,H.v4)();this.logger.debug(`Adding agent with id: ${u}`),this.agents.set(u,e);let c={id:u,location:{context:o,tabId:r,frameId:i},createdAt:Date.now(),lastActiveAt:Date.now()};this.agentsInfo.set(u,c),this.logger.debug(`Constructed agent info: ${JSON.stringify(c)}`),e.onMessage.addListener(d=>this.emit("agentMessage",d,c));let p={port:e,info:c};return e.onDisconnect.addListener(()=>{this.emit("agentDisconnect",c),this.logger.debug("Agent disconnected, removing from manager. ",{agentInfo:c}),this.removeAgent(u)}),this.emit("agentSetup",p),this.logger.debug("Setup complete for adding agent. ",{agentInfo:c}),u}getAgentByLocation(e){let{context:t,tabId:n,frameId:o}=e,r=Array.from(this.agentsInfo.entries()).find(([c,p])=>p.location.context===t&&p.location.tabId===n&&p.location.frameId===o);if(r===void 0)return this.logger.error("No agent found for location. ",{location:e}),null;let i=r[0],a=this.agents.get(i),u=this.agentsInfo.get(i);return!a||!u?(this.logger.error("No agent found for location. ",{location:e}),null):{port:a,info:u}}getAgentsByContext(e){return Array.from(this.agentsInfo.entries()).filter(([n,o])=>o.location.context===e).map(([n,o])=>({port:this.agents.get(n),info:o}))}getAllAgents(){return Array.from(this.agentsInfo.entries()).map(([t,n])=>({port:this.agents.get(t),info:n}))}queryAgents(e){return Array.from(this.agentsInfo.entries()).filter(([n,o])=>{let r=e.context?o.location.context===e.context:!0,i=e.tabId?o.location.tabId===e.tabId:!0,a=e.frameId?o.location.frameId===e.frameId:!0;return r&&i&&a}).map(([n,o])=>({port:this.agents.get(n),info:o}))}getAgentById(e){let t=this.agents.get(e),n=this.agentsInfo.get(e);return!t||!n?(this.logger.error("No agent found for agentId. ",{id:e}),null):{port:t,info:n}}getAllAgentsInfo(){return Array.from(this.agentsInfo.values())}hasPort(e){return!!Array.from(this.agents.values()).find(n=>n.name===e.name)}removeAgent(e){this.agents.has(e)&&this.agentsInfo.has(e)?(this.agents.delete(e),this.agentsInfo.delete(e)):this.logger.error("No agent found to remove. ",{agentId:e})}printAgents(){let e=Array.from(this.agents.entries()),t=Array.from(this.agentsInfo.entries());this.logger.debug("Current agents:",{allAgents:e,allAgentsInfo:t})}on(e,t){let n=this.eventHandlers.get(e);n&&n.add(t)}emit(e,...t){let n=this.eventHandlers.get(e);n==null||n.forEach(o=>o(...t))}identifyConnectionSource(e){var y,d,A,M,v,C,w;let t=e.sender;if(!t)return this.logger.error("Cannot add agent that did not have a sender"),null;let n=F.default.runtime.getManifest(),o=((y=n==null?void 0:n.side_panel)==null?void 0:y.default_path)||"",r=n.options_page||"",i=((d=n.action)==null?void 0:d.default_popup)||"",a=n.devtools_page||"",u=((A=n.chrome_url_overrides)==null?void 0:A.newtab)||"",c=((M=n.chrome_url_overrides)==null?void 0:M.bookmarks)||"",p=((v=n.chrome_url_overrides)==null?void 0:v.history)||"",b={sidepanel:o?o.split("/").pop():"sidepanel.html",options:r?r.split("/").pop():"options.html",popup:i?i.split("/").pop():"popup.html",devtools:a?a.split("/").pop():"devtools.html",newtab:u?u.split("/").pop():"newtab.html",bookmarks:c?c.split("/").pop():"bookmarks.html",history:p?p.split("/").pop():"history.html"};if(t.tab&&t.url&&!t.url.includes("extension://"))return{context:"contentscript",tabId:t.tab.id,frameId:t.frameId||0,url:t.url,portName:e.name};if(t.url&&t.url.includes("extension://")){let G=new URL(t.url).pathname.split("/").pop();for(let[W,_]of Object.entries(b))if(G===_)return{context:W,tabId:((C=t.tab)==null?void 0:C.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name};return{context:"unknown",tabId:((w=t.tab)==null?void 0:w.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name}}return{context:"unknown",tabId:0,url:t.url,portName:e.name}}};var x=class{constructor(e,t,n){this.agentOperations=e;this.namespace=t;this.logger=n}handleConnection(e){try{if(this.logger.info("New connection request:",e.name),!e.name)throw new g("invalid-context","Port name not provided");if(!e.name||!e.name.startsWith(this.namespace+":"))throw new g("invalid-context",`Invalid namespace or port name format. port name was ${(e==null?void 0:e.name)||"port undefined"} but namespace is ${this.namespace}`);e.onMessage.addListener(this.handleInitMessage.bind(this,e)),setTimeout(()=>{if(!this.agentOperations.hasPort(e))try{e.disconnect()}catch(t){this.logger.error("Failed to disconnect port:",t)}},5e3)}catch(t){this.handleConnectionError(e,t)}}handleInitMessage(e,t){if(t.action==="porter-init")try{e.onMessage.removeListener(this.handleInitMessage.bind(this,e));let{connectionId:n}=t.payload;if(!n)throw new g("invalid-context","Missing context or connection ID. Message was: "+JSON.stringify(t));let o=this.agentOperations.addAgent(e);if(!o)throw new g("invalid-context","Failed to add agent");let r=this.agentOperations.getAgentById(o);r&&this.confirmConnection(r),this.agentOperations.printAgents()}catch(n){this.handleConnectionError(e,n)}}handleConnectionError(e,t){let n=t instanceof g?t:new g("connection-failed",t instanceof Error?t.message:"Unknown connection error",{originalError:t});this.logger.error("Connection handling failed: ",{porterError:n});try{e.postMessage({action:"porter-error",payload:{error:n}})}catch(o){this.logger.error("Failed to send error message: ",{error:o})}try{e.disconnect()}catch(o){this.logger.error("Failed to disconnect port: ",{error:o})}}confirmConnection(e){if(this.logger.debug("Sending confirmation message back to initiator ",{agent:e}),!e.port)throw new g("invalid-port","Agent port is undefined when confirming connection");e.port.postMessage({action:"porter-handshake",payload:{info:e.info,currentConnections:this.agentOperations.getAllAgentsInfo()}})}};var S=class{constructor(e,t){this.agentOperations=e;this.logger=t;this.eventListeners=new Map;this.messageListeners=new Set;this.initializationHandler={"porter-messages-established":(n,o)=>{var i;if(!o||!o.id)return;let r=(i=this.agentOperations.getAgentById(o.id))==null?void 0:i.info;if(!r){this.logger.error("No agent info found for agent id: ",o.id);return}this.logger.debug("internalHandlers, established message received: ",o.id,n),this.emitEvent("onMessagesSet",r)}}}async post(e,t){return new Promise((n,o)=>{try{this.logger.debug("Post request received:",{action:e.action,target:t});let r=setTimeout(()=>{let i=new Error("Message posting timed out");this.logger.error("Post timeout:",i),o(i)},5e3);t===void 0?this.broadcastMessage(e):te(t)?this.postToLocation(e,t):ne(t)?this.postToContext(e,t):typeof t=="string"?this.postToId(e,t):this.postToTab(e,t),clearTimeout(r),n()}catch(r){let i=r instanceof Error?r.message:"Unknown error";this.logger.error("Failed to post message:",i),o(new Error(`Failed to post message: ${i}`))}})}broadcastMessage(e){this.logger.info("Broadcasting message to all agents: ",e),this.agentOperations.getAllAgents().forEach(t=>{t.port&&t.port.postMessage(e)})}postToTab(e,t){let n=this.agentOperations.queryAgents({context:"contentscript",tabId:t});if(n.length===0){throw this.logger.warn("post: No agents found for tab: ",t),new g("message-failed",`Failed to post message to tabId ${t}`,{originalError:e});return}n.forEach(o=>{o.port&&this.postToPort(e,o.port)})}postToLocation(e,t){this.agentOperations.queryAgents(t).forEach(o=>{if(!o.port)throw new g("invalid-target","No port found for agent",{agentInfo:o.info});this.postToPort(e,o.port)})}postToContext(e,t){this.agentOperations.queryAgents({context:t}).forEach(o=>{if(!o.port)throw new g("invalid-target","No port found for agent",{agentInfo:o.info});this.postToPort(e,o.port)})}postToPort(e,t){try{t.postMessage(e)}catch(n){throw new g("message-failed","Failed to post message to port",{originalError:n,message:e})}}postToId(e,t){let n=this.agentOperations.getAgentById(t);if(!(n!=null&&n.port))throw new g("invalid-target",`No agent found for key: ${t}`);this.postToPort(e,n.port)}onMessage(e){Array.from(this.messageListeners).find(o=>JSON.stringify(o.config)===JSON.stringify(e))&&this.logger.warn(`Listener with same config already exists: ${JSON.stringify(e)}`);let n={config:e,listener:o=>{let r=e[o.message.action];if(r){this.logger.debug("onMessage, calling handler ",{event:o});let{message:i,...a}=o;r(i,a)}else this.logger.debug("onMessage, no handler found ",{event:o})}};return this.messageListeners.add(n),()=>{this.messageListeners.delete(n)}}on(e){return this.onMessage(e)}handleIncomingMessage(e,t){this.logger.debug("Received message",{message:e,info:t}),this.emitMessage({...t,message:e})}emitEvent(e,t){var n;this.logger.debug("emitting event: ",e,t),(n=this.eventListeners.get(e))==null||n.forEach(o=>o(t))}emitMessage(e){if(this.logger.debug("Dispatching incoming message to subscribers",{messageEvent:e}),e.message.action.startsWith("porter-")){let n=this.initializationHandler[e.message.action];if(n){this.logger.debug("Internal message being handled",{messageEvent:e});let{message:o,...r}=e;n(o,r);return}}e.message.target&&(this.logger.debug("Relaying message to target:",e.message.target),this.post(e.message,e.message.target));let t=0;this.logger.trace("Processing message with registered handlers");for(let{listener:n,config:o}of this.messageListeners)o[e.message.action]&&(n(e),t++,this.logger.debug("Message handled by registered listener: ",{listener:n,config:o}));t===0?this.logger.warn("No handler found for message:",e.message.action):this.logger.debug(`Message handled by ${t} registered listeners`)}addListener(e,t){return this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t),()=>{var n;(n=this.eventListeners.get(e))==null||n.delete(t)}}handleDisconnect(e){this.messageListeners.forEach(t=>{t.config[e.id]&&this.messageListeners.delete(t)}),this.logger.info("Agent disconnected:",{info:e}),this.emitEvent("onDisconnect",e)}handleConnect(e){this.logger.info("Agent connected:",{info:e}),this.emitEvent("onConnect",e)}onConnect(e){return this.addListener("onConnect",e)}onMessagesSet(e){return this.addListener("onMessagesSet",e)}onDisconnect(e){return this.addListener("onDisconnect",e)}};function te(s){return typeof s=="object"&&s!==null&&"context"in s&&"tabId"in s&&"frameId"in s}function ne(s){return typeof s=="string"&&Object.values(L).includes(s)}var m=class m{constructor(e,t){if((t==null?void 0:t.debug)!==void 0&&f.configure({enabled:t.debug}),this.logger=f.getLogger("SW"),this.namespace=e||"porter",e||this.logger.error('No namespace provided, defaulting to "porter"'),this.agentManager=new E(this.logger),this.messageHandler=new S(this.agentManager,this.logger),this.connectionManager=new x(this.agentManager,this.namespace,this.logger),this.logger.info(`Constructing Porter with namespace: ${this.namespace}`),!Q())throw new g("invalid-context","Can only create in a service worker");this.agentManager.on("agentMessage",(n,o)=>{this.messageHandler.handleIncomingMessage(n,o)}),this.agentManager.on("agentDisconnect",n=>{this.messageHandler.handleDisconnect(n)}),this.agentManager.on("agentSetup",n=>{this.logger.debug("Handling agent setup",{agent:n}),this.messageHandler.handleConnect(n.info),this.connectionManager.confirmConnection(n)}),z.default.runtime.onConnect.addListener(this.connectionManager.handleConnection.bind(this.connectionManager))}static getInstance(e="porter",t){return m.staticLogger.debug(`Getting instance for namespace: ${e}`),m.instances.has(e)?(t==null?void 0:t.debug)!==void 0&&f.configure({enabled:t.debug}):(m.staticLogger.info(`Creating new instance for namespace: ${e}`),m.instances.set(e,new m(e,t))),m.instances.get(e)}post(e,t){return this.messageHandler.post(e,t)}onMessage(e){return this.messageHandler.onMessage(e)}on(e){return this.messageHandler.on(e)}onConnect(e){return this.messageHandler.onConnect(e)}onDisconnect(e){return this.messageHandler.onDisconnect(e)}onMessagesSet(e){return this.messageHandler.onMessagesSet(e)}getInfo(e){var t;return((t=this.agentManager.getAgentById(e))==null?void 0:t.info)||null}getAgentById(e){return this.agentManager.getAgentById(e)}getAgentByLocation(e){return this.agentManager.getAgentByLocation(e)}queryAgents(e){return this.agentManager.queryAgents(e)}};m.instances=new Map,m.staticLogger=f.getLogger("SW");var U=m;var V=D(require("webextension-polyfill"));var O=class{constructor(e){this.queue=[];this.maxQueueSize=1e3;this.maxMessageAge=5*60*1e3;this.logger=e,this.logger.debug("MessageQueue initialized",{maxQueueSize:this.maxQueueSize,maxMessageAge:`${this.maxMessageAge/1e3} seconds`})}enqueue(e,t){let n=this.queue.length;this.cleanup(),n!==this.queue.length&&this.logger.debug(`Cleaned up ${n-this.queue.length} old messages`),this.queue.length>=this.maxQueueSize&&(this.logger.warn("Message queue is full, dropping oldest message",{queueSize:this.queue.length,maxSize:this.maxQueueSize}),this.queue.shift()),this.queue.push({message:e,target:t,timestamp:Date.now()}),this.logger.debug("Message queued",{queueSize:this.queue.length,message:e,target:t,timestamp:new Date().toISOString()})}dequeue(){let e=[...this.queue];return this.queue=[],this.logger.info(`Dequeued ${e.length} messages`,{oldestMessage:e[0]?new Date(e[0].timestamp).toISOString():null,newestMessage:e[e.length-1]?new Date(e[e.length-1].timestamp).toISOString():null}),e}isEmpty(){return this.queue.length===0}cleanup(){let e=Date.now(),t=this.queue.length;this.queue=this.queue.filter(n=>e-n.timestamp<this.maxMessageAge),t!==this.queue.length&&this.logger.debug(`Cleaned up ${t-this.queue.length} expired messages`,{remaining:this.queue.length,maxAge:`${this.maxMessageAge/1e3} seconds`})}};var N=class{constructor(e,t){this.namespace=e;this.CONNECTION_TIMEOUT=5e3;this.RECONNECT_INTERVAL=1e3;this.connectionTimer=null;this.reconnectTimer=null;this.agentInfo=null;this.port=null;this.isReconnecting=!1;this.reconnectAttemptCount=0;this.connectionId=`${Date.now()}-${Math.random().toString(36).substring(2,9)}`,this.logger=t,this.messageQueue=new O(t)}async initializeConnection(){var e;try{this.connectionTimer&&clearTimeout(this.connectionTimer);let t=`${this.namespace}:${this.connectionId}`;this.logger.debug("Connecting new port with name: ",{portName:t}),this.port=V.default.runtime.connect({name:t});let n=new Promise((o,r)=>{var u;let i=setTimeout(()=>r(new g("connection-timeout","Connection timed out waiting for handshake")),this.CONNECTION_TIMEOUT),a=c=>{var p,b;c.action==="porter-handshake"?(this.logger.debug("Received handshake:",c),clearTimeout(i),this.agentInfo=c.payload.info,this.logger.debug("Handshake agent info:",{agentInfo:this.agentInfo}),(p=this.port)==null||p.onMessage.removeListener(a),o()):c.action==="porter-error"&&(clearTimeout(i),(b=this.port)==null||b.onMessage.removeListener(a),this.logger.error("Error:",c),r(new g(c.payload.type,c.payload.message,c.payload.details)))};(u=this.port)==null||u.onMessage.addListener(a)});(e=this.port)==null||e.postMessage({action:"porter-init",payload:{info:this.agentInfo,connectionId:this.connectionId}}),await n,await this.processQueuedMessages()}catch(t){throw this.logger.error("Connection initialization failed:",t),this.handleDisconnect(this.port),t}}async processQueuedMessages(){if(!this.port||this.messageQueue.isEmpty())return;let e=this.messageQueue.dequeue();this.logger.info(`Processing ${e.length} queued messages after reconnection`);for(let{message:t,target:n}of e)try{this.port.postMessage({action:"porter-message",payload:{message:t,target:n}}),this.logger.debug("Successfully resent queued message:",{message:t,target:n})}catch(o){this.logger.error("Failed to process queued message:",o),this.messageQueue.enqueue(t,n),this.logger.debug("Re-queued failed message for retry")}}getPort(){return this.port}getAgentInfo(){return this.agentInfo}getNamespace(){return this.namespace}handleDisconnect(e){this.logger.info("Port disconnected",{portName:e.name,connectionId:this.connectionId,queuedMessages:this.messageQueue.isEmpty()?0:"some"}),this.port=null,this.agentInfo=null,this.isReconnecting||this.startReconnectionAttempts()}startReconnectionAttempts(){this.isReconnecting=!0,this.reconnectAttemptCount=0,this.reconnectTimer&&clearInterval(this.reconnectTimer),this.logger.info("Starting reconnection attempts",{interval:this.RECONNECT_INTERVAL,queuedMessages:this.messageQueue.isEmpty()?0:"some"}),this.reconnectTimer=setInterval(async()=>{this.reconnectAttemptCount++;try{this.logger.debug(`Reconnection attempt ${this.reconnectAttemptCount}`),await this.initializeConnection(),this.isReconnecting=!1,this.reconnectTimer&&clearInterval(this.reconnectTimer),this.logger.info("Reconnection successful",{attempts:this.reconnectAttemptCount,queuedMessages:this.messageQueue.isEmpty()?0:"some"})}catch(e){this.logger.debug(`Reconnection attempt ${this.reconnectAttemptCount} failed:`,e)}},this.RECONNECT_INTERVAL)}queueMessage(e,t){this.messageQueue.enqueue(e,t),this.logger.debug("Message queued for retry",{message:e,target:t,queueSize:this.messageQueue.isEmpty()?0:"some"})}};var R=class{constructor(e){this.logger=e;this.MAX_QUEUE_SIZE=1e3;this.MESSAGE_TIMEOUT=3e4;this.messageQueue=[];this.handlers=new Map}handleMessage(e,t){if(this.logger.debug("handleMessage, message: ",t),this.handlers.size===0){if(this.messageQueue.length>=this.MAX_QUEUE_SIZE){this.logger.warn("Message queue full, dropping message:",t);return}this.logger.warn("No message handlers configured yet, queueing message: ",t),this.messageQueue.push({message:t,timestamp:Date.now()});return}this.processMessage(e,t)}onMessage(e){this.logger.debug("Setting message handlers from config: ",e),this.handlers.clear(),this.on(e),this.processQueuedMessages()}on(e){this.logger.debug("Adding message handlers from config: ",e),Object.entries(e).forEach(([t,n])=>{this.handlers.has(t)||this.handlers.set(t,[]),this.handlers.get(t).push(n)}),this.processQueuedMessages()}processQueuedMessages(){for(;this.messageQueue.length>0;){let e=this.messageQueue[0];if(Date.now()-e.timestamp>this.MESSAGE_TIMEOUT){this.logger.warn("Message timeout, dropping message: ",this.messageQueue.shift());continue}this.processMessage(null,e.message),this.messageQueue.shift()}}processMessage(e,t){let n=t.action,o=this.handlers.get(n)||[];o.length>0?(this.logger.debug(`Found ${o.length} handlers for action: ${n}`),o.forEach(r=>r(t))):this.logger.debug(`No handlers for message with action: ${n}`)}post(e,t,n){this.logger.debug("Sending message",{action:t.action,target:n,hasPayload:!!t.payload});try{n&&(t.target=n),e.postMessage(t)}catch(o){throw new g("message-failed","Failed to post message",{originalError:o,message:t,target:n})}}};var I=class I{constructor(e={}){let t=e.namespace??"porter",n=e.agentContext??this.determineContext();e.debug!==void 0&&f.configure({enabled:e.debug}),this.logger=f.getLogger("Agent"),this.connectionManager=new N(t,this.logger),this.messageHandler=new R(this.logger),this.logger.info("Initializing with options: ",{options:e,context:n}),this.initializeConnection()}static getInstance(e={}){return!I.instance||I.instance.connectionManager.getNamespace()!==e.namespace?I.instance=new I(e):e.debug!==void 0&&f.configure({enabled:e.debug}),I.instance}async initializeConnection(){await this.connectionManager.initializeConnection();let e=this.connectionManager.getPort();e&&(e.onMessage.addListener(t=>this.messageHandler.handleMessage(e,t)),e.onDisconnect.addListener(t=>this.connectionManager.handleDisconnect(t)))}onMessage(e){this.messageHandler.onMessage(e);let t=this.connectionManager.getPort();t==null||t.postMessage({action:"porter-messages-established"})}on(e){this.messageHandler.on(e);let t=this.connectionManager.getPort();t==null||t.postMessage({action:"porter-messages-established"})}post(e,t){let n=this.connectionManager.getPort();if(this.logger.debug("Posting message",{message:e,target:t,port:n}),n)try{this.messageHandler.post(n,e,t)}catch(o){this.logger.error("Failed to post message, queueing for retry",{error:o}),this.connectionManager.queueMessage(e,t)}else this.logger.debug("No port found, queueing message",{message:e,target:t}),this.connectionManager.queueMessage(e,t)}determineContext(){return window.location.protocol.includes("extension")?"extension":"contentscript"}getAgentInfo(){return this.connectionManager.getAgentInfo()||null}};I.instance=null;var q=I;function B(s){let e=q.getInstance(s);return{type:"agent",post:e.post.bind(e),onMessage:e.onMessage.bind(e),on:e.on.bind(e),getAgentInfo:e.getAgentInfo.bind(e)}}function k(s){let[e,t]=(0,h.useState)(!1),[n,o]=(0,h.useState)(null),[r,i]=(0,h.useState)(null),a=(0,h.useRef)(null),u=(0,h.useRef)(null),c=(0,h.useRef)(null),p=(0,h.useMemo)(()=>({agentContext:s==null?void 0:s.agentContext,namespace:s==null?void 0:s.namespace,debug:s==null?void 0:s.debug}),[s==null?void 0:s.agentContext,s==null?void 0:s.namespace,s==null?void 0:s.debug]);(0,h.useEffect)(()=>{let d=!0;return(async()=>{try{let{post:M,on:v,getAgentInfo:C}=B(p);d&&(a.current=M,u.current=v,c.current=C,t(!0),o(null),v({"porter-handshake":w=>{console.log("[PORTER] porter-handshake heard: ",w.payload),d&&i(w.payload.info)}}))}catch(M){d&&(console.log("[PORTER] initializePorter error ",M),o(M instanceof Error?M:new Error("Failed to connect to Porter")),t(!1))}})(),()=>{d=!1}},[p]);let b=(0,h.useCallback)(d=>{if(a.current)try{a.current(d)}catch(A){o(A instanceof Error?A:new Error("Failed to send message"))}else o(new Error("Porter is not connected"))},[]),y=(0,h.useCallback)(d=>{if(u.current)try{u.current(d)}catch(A){o(A instanceof Error?A:new Error("Failed to set message handlers"))}else o(new Error("Porter is not connected"))},[]);return{post:b,on:y,isConnected:e,error:n,agentInfo:r}}0&&(module.exports={usePorter}); //# sourceMappingURL=index.js.map