crann 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/react.js +1 -1
- package/dist/cjs/react.js.map +3 -3
- package/dist/esm/react.js +1 -1
- package/dist/esm/react.js.map +3 -3
- package/package.json +1 -1
package/dist/cjs/react.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var ne=Object.create;var P=Object.defineProperty;var oe=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var se=Object.getPrototypeOf,ie=Object.prototype.hasOwnProperty;var ae=(r,e)=>{for(var t in e)P(r,t,{get:e[t],enumerable:!0})},G=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of re(e))!ie.call(r,o)&&o!==t&&P(r,o,{get:()=>e[o],enumerable:!(n=oe(e,o))||n.enumerable});return r};var H=(r,e,t)=>(t=r!=null?ne(se(r)):{},G(e||!r||!r.__esModule?P(t,"default",{value:r,enumerable:!0}):t,r)),ce=r=>G(P({},"__esModule",{value:!0}),r);var de={};ae(de,{createCrannHooks:()=>ee});module.exports=ce(de);var p=require("react");var J=H(require("webextension-polyfill"));var w=(a=>(a.ContentScript="contentscript",a.Extension="extension",a.Popup="popup",a.Sidepanel="sidepanel",a.Devtools="devtools",a.Options="options",a.Unknown="unknown",a))(w||{});var u=class extends Error{constructor(t,n,o){super(n);this.type=t;this.details=o;this.name="PorterError"}};function j(){return typeof ServiceWorkerGlobalScope<"u"&&self instanceof ServiceWorkerGlobalScope}var d=class d{constructor(e){this.context=e}static getLevel(){var t,n,o;return((t=d.globalOptions)==null?void 0:t.level)!==void 0?d.globalOptions.level:typeof process<"u"&&(((n=process.env)==null?void 0:n.NODE_ENV)==="production"||((o=process.env)==null?void 0:o.PORTER_ENV)==="production")?1:4}static configure(e){d.globalOptions=e,e.level!==void 0&&(d.level=e.level),e.enabled!==void 0&&(d.enabled=e.enabled)}static getLogger(e){return this.instances.has(e)||this.instances.set(e,new d(e)),this.instances.get(e)}error(e,...t){d.enabled&&d.level>=0&&console.error(`[Porter:${this.context}] ${e}`,...t)}warn(e,...t){d.enabled&&d.level>=1&&console.warn(`[Porter:${this.context}] ${e}`,...t)}info(e,...t){d.enabled&&d.level>=2&&console.info(`[Porter:${this.context}] ${e}`,...t)}debug(e,...t){d.enabled&&d.level>=3&&console.debug(`[Porter:${this.context}] ${e}`,...t)}trace(e,...t){d.enabled&&d.level>=4&&console.trace(`[Porter:${this.context}] ${e}`,...t)}};d.level=d.getLevel(),d.enabled=!1,d.instances=new Map;var A=d;var K=H(require("webextension-polyfill")),W=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 g,h;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,s=n.tabId||-1,i=n.frameId||0;this.logger.debug("Determined context for new agent",{determinedContext:o,tabId:s,frameId:i});let a=Array.from(this.agentsInfo.values()).filter(m=>m.location.context===o&&m.location.tabId===s&&m.location.frameId===i);a.length>0&&this.logger.debug("Adding agent: Found existing similar agent.",{tabAgentsInfo:a});let l=((h=(g=this.getAgentByLocation({context:o,tabId:s,frameId:i}))==null?void 0:g.info)==null?void 0:h.id)||(0,W.v4)();this.logger.debug(`Adding agent with id: ${l}`),this.agents.set(l,e);let f={id:l,location:{context:o,tabId:s,frameId:i},createdAt:Date.now(),lastActiveAt:Date.now()};this.agentsInfo.set(l,f),this.logger.debug(`Constructed agent info: ${JSON.stringify(f)}`),e.onMessage.addListener(m=>this.emit("agentMessage",m,f));let c={port:e,info:f};return e.onDisconnect.addListener(()=>{this.emit("agentDisconnect",f),this.logger.debug("Agent disconnected, removing from manager. ",{agentInfo:f}),this.removeAgent(l)}),this.emit("agentSetup",c),this.logger.debug("Setup complete for adding agent. ",{agentInfo:f}),l}getAgentByLocation(e){let{context:t,tabId:n,frameId:o}=e,s=Array.from(this.agentsInfo.entries()).find(([f,c])=>c.location.context===t&&c.location.tabId===n&&c.location.frameId===o);if(s===void 0)return this.logger.error("No agent found for location. ",{location:e}),null;let i=s[0],a=this.agents.get(i),l=this.agentsInfo.get(i);return!a||!l?(this.logger.error("No agent found for location. ",{location:e}),null):{port:a,info:l}}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 s=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 s&&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 h,m,y,I,b,C,M;let t=e.sender;if(!t)return this.logger.error("Cannot add agent that did not have a sender"),null;let n=K.default.runtime.getManifest(),o=((h=n==null?void 0:n.side_panel)==null?void 0:h.default_path)||"",s=n.options_page||"",i=((m=n.action)==null?void 0:m.default_popup)||"",a=n.devtools_page||"",l=((y=n.chrome_url_overrides)==null?void 0:y.newtab)||"",f=((I=n.chrome_url_overrides)==null?void 0:I.bookmarks)||"",c=((b=n.chrome_url_overrides)==null?void 0:b.history)||"",g={sidepanel:o?o.split("/").pop():"sidepanel.html",options:s?s.split("/").pop():"options.html",popup:i?i.split("/").pop():"popup.html",devtools:a?a.split("/").pop():"devtools.html",newtab:l?l.split("/").pop():"newtab.html",bookmarks:f?f.split("/").pop():"bookmarks.html",history:c?c.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 z=new URL(t.url).pathname.split("/").pop();for(let[_,T]of Object.entries(g))if(z===T)return{context:_,tabId:((C=t.tab)==null?void 0:C.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name};return{context:"unknown",tabId:((M=t.tab)==null?void 0:M.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name}}return{context:"unknown",tabId:0,url:t.url,portName:e.name}}};var L=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 u("invalid-context","Port name not provided");if(!e.name||!e.name.startsWith(this.namespace+":"))throw new u("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 u("invalid-context","Missing context or connection ID. Message was: "+JSON.stringify(t));let o=this.agentOperations.addAgent(e);if(!o)throw new u("invalid-context","Failed to add agent");let s=this.agentOperations.getAgentById(o);s&&this.confirmConnection(s),this.agentOperations.printAgents()}catch(n){this.handleConnectionError(e,n)}}handleConnectionError(e,t){let n=t instanceof u?t:new u("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 u("invalid-port","Agent port is undefined when confirming connection");e.port.postMessage({action:"porter-handshake",payload:{info:e.info,currentConnections:this.agentOperations.getAllAgentsInfo()}})}};var R=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 s=(i=this.agentOperations.getAgentById(o.id))==null?void 0:i.info;if(!s){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",s)}}}async post(e,t){return new Promise((n,o)=>{try{this.logger.debug("Post request received:",{action:e.action,target:t});let s=setTimeout(()=>{let i=new Error("Message posting timed out");this.logger.error("Post timeout:",i),o(i)},5e3);t===void 0?this.broadcastMessage(e):ge(t)?this.postToLocation(e,t):le(t)?this.postToContext(e,t):typeof t=="string"?this.postToId(e,t):this.postToTab(e,t),clearTimeout(s),n()}catch(s){let i=s instanceof Error?s.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 u("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 u("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 u("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 u("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 u("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 s=e[o.message.action];if(s){this.logger.debug("onMessage, calling handler ",{event:o});let{message:i,...a}=o;s(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,...s}=e;n(o,s);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 ge(r){return typeof r=="object"&&r!==null&&"context"in r&&"tabId"in r&&"frameId"in r}function le(r){return typeof r=="string"&&Object.values(w).includes(r)}var v=class v{constructor(e,t){if((t==null?void 0:t.debug)!==void 0&&A.configure({enabled:t.debug}),this.logger=A.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 R(this.agentManager,this.logger),this.connectionManager=new L(this.agentManager,this.namespace,this.logger),this.logger.info(`Constructing Porter with namespace: ${this.namespace}`),!j())throw new u("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)}),J.default.runtime.onConnect.addListener(this.connectionManager.handleConnection.bind(this.connectionManager))}static getInstance(e="porter",t){return v.staticLogger.debug(`Getting instance for namespace: ${e}`),v.instances.has(e)?(t==null?void 0:t.debug)!==void 0&&A.configure({enabled:t.debug}):(v.staticLogger.info(`Creating new instance for namespace: ${e}`),v.instances.set(e,new v(e,t))),v.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)}};v.instances=new Map,v.staticLogger=A.getLogger("SW");var X=v;var Z=H(require("webextension-polyfill"));var k=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.disconnectCallbacks=new Set;this.reconnectCallbacks=new Set;this.connectionId=`${Date.now()}-${Math.random().toString(36).substring(2,9)}`,this.logger=t,this.messageQueue=new k(t)}onDisconnect(e){return this.disconnectCallbacks.add(e),()=>{this.disconnectCallbacks.delete(e)}}onReconnect(e){return this.reconnectCallbacks.add(e),()=>{this.reconnectCallbacks.delete(e)}}emitDisconnect(){this.logger.debug("Emitting disconnect event",{callbackCount:this.disconnectCallbacks.size}),this.disconnectCallbacks.forEach(e=>{try{e()}catch(t){this.logger.error("Error in disconnect callback:",t)}})}emitReconnect(e){this.logger.debug("Emitting reconnect event",{callbackCount:this.reconnectCallbacks.size,info:e}),this.reconnectCallbacks.forEach(t=>{try{t(e)}catch(n){this.logger.error("Error in reconnect callback:",n)}})}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=Z.default.runtime.connect({name:t});let n=new Promise((o,s)=>{var l;let i=setTimeout(()=>s(new u("connection-timeout","Connection timed out waiting for handshake")),this.CONNECTION_TIMEOUT),a=f=>{var c,g;f.action==="porter-handshake"?(this.logger.debug("Received handshake:",f),clearTimeout(i),this.agentInfo=f.payload.info,this.logger.debug("Handshake agent info:",{agentInfo:this.agentInfo}),(c=this.port)==null||c.onMessage.removeListener(a),o()):f.action==="porter-error"&&(clearTimeout(i),(g=this.port)==null||g.onMessage.removeListener(a),this.logger.error("Error:",f),s(new u(f.payload.type,f.payload.message,f.payload.details)))};(l=this.port)==null||l.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{let o={...t};n&&(o.target=n),this.port.postMessage(o),this.logger.debug("Successfully resent queued message:",{message:o})}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.emitDisconnect(),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.reconnectTimer=null),this.logger.info("Reconnection successful",{attempts:this.reconnectAttemptCount,queuedMessages:this.messageQueue.isEmpty()?0:"some"}),this.agentInfo&&this.emitReconnect(this.agentInfo)}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 O=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(s=>s(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 u("message-failed","Failed to post message",{originalError:o,message:t,target:n})}}};var S=class S{constructor(e={}){let t=e.namespace??"porter",n=e.agentContext??this.determineContext();e.debug!==void 0&&A.configure({enabled:e.debug}),this.logger=A.getLogger("Agent"),this.connectionManager=new N(t,this.logger),this.messageHandler=new O(this.logger),this.connectionManager.onReconnect(o=>{this.logger.info("Reconnected, re-wiring port listeners",{info:o}),this.setupPortListeners()}),this.logger.info("Initializing with options: ",{options:e,context:n}),this.initializeConnection()}static getInstance(e={}){return!S.instance||S.instance.connectionManager.getNamespace()!==e.namespace?S.instance=new S(e):e.debug!==void 0&&A.configure({enabled:e.debug}),S.instance}async initializeConnection(){await this.connectionManager.initializeConnection(),this.setupPortListeners()}setupPortListeners(){let e=this.connectionManager.getPort();e?(this.logger.debug("Setting up port listeners"),e.onMessage.addListener(t=>this.messageHandler.handleMessage(e,t)),e.onDisconnect.addListener(t=>this.connectionManager.handleDisconnect(t))):this.logger.warn("Cannot setup port listeners: no port available")}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}onDisconnect(e){return this.connectionManager.onDisconnect(e)}onReconnect(e){return this.connectionManager.onReconnect(e)}};S.instance=null;var F=S;function q(r){let e=F.getInstance(r);return{type:"agent",post:e.post.bind(e),onMessage:e.onMessage.bind(e),on:e.on.bind(e),getAgentInfo:e.getAgentInfo.bind(e),onDisconnect:e.onDisconnect.bind(e),onReconnect:e.onReconnect.bind(e)}}var x=require("react");var Q=class extends Error{constructor(e){super(e),this.name="CrannError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}};var $=class extends Q{constructor(t,n){super(`${n==="store"?"Store":"Agent"} "${t}" has been ${n==="store"?"destroyed":"disconnected"} and cannot be used.`);this.storeName=t;this.entity=n;this.name="LifecycleError"}};var B=class{constructor(e,t={}){this._agentInfo=null;this._isConnected=!1;this._isDisconnected=!1;this.subscribers=new Set;this.readyCallbacks=new Set;this.disconnectCallbacks=new Set;this.reconnectCallbacks=new Set;this.config=e,this.options=t,this._state=this.buildDefaultState(),this.readyPromise=new Promise(n=>{this.readyResolve=n}),this.porter=q({namespace:e.name,debug:t.debug??!1}),this.setupMessageHandlers(),this.actionsProxy=this.createActionsProxy()}ready(){return this.assertNotDisconnected(),this.readyPromise}onReady(e){return this.assertNotDisconnected(),this._isConnected&&setTimeout(()=>e(this._state),0),this.readyCallbacks.add(e),()=>{this.readyCallbacks.delete(e)}}getState(){return this.assertNotDisconnected(),{...this._state}}get state(){return this.getState()}async setState(e){this.assertNotDisconnected(),this._state={...this._state,...e},this.porter.post({action:"setState",payload:{state:e}})}subscribe(e,t){this.assertNotDisconnected();let n,o;typeof e=="function"?o=e:(n=e,o=t);let s={keys:n,callback:o};return this.subscribers.add(s),()=>{this.subscribers.delete(s)}}get actions(){return this.assertNotDisconnected(),this.actionsProxy}getInfo(){return this._agentInfo?{id:this._agentInfo.id,tabId:this._agentInfo.location.tabId,frameId:this._agentInfo.location.frameId,context:this._agentInfo.location.context}:null}onDisconnect(e){return this.assertNotDisconnected(),this.disconnectCallbacks.add(e),()=>{this.disconnectCallbacks.delete(e)}}onReconnect(e){return this.assertNotDisconnected(),this.reconnectCallbacks.add(e),()=>{this.reconnectCallbacks.delete(e)}}disconnect(){this._isDisconnected||(this._isDisconnected=!0,this._isConnected=!1,this.subscribers.clear(),this.readyCallbacks.clear(),this.disconnectCallbacks.clear(),this.reconnectCallbacks.clear())}setupMessageHandlers(){this.porter.on({initialState:e=>{let{state:t,info:n}=e.payload;this._state=t,this._agentInfo=n,this._isConnected=!0,this.readyResolve(this._state),this.readyCallbacks.forEach(o=>{try{o(this._state)}catch(s){console.error("[Crann Agent] Error in onReady callback:",s)}}),this.notifySubscribers(t)},stateUpdate:e=>{let{state:t}=e.payload;this._state={...this._state,...t},this.notifySubscribers(t)},rpcResult:e=>{}}),this.porter.onDisconnect(()=>{this._isConnected=!1,this.disconnectCallbacks.forEach(e=>{try{e()}catch(t){console.error("[Crann Agent] Error in onDisconnect callback:",t)}})}),this.porter.onReconnect(e=>{this._agentInfo=e,this._isConnected=!0,this.reconnectCallbacks.forEach(t=>{try{t(this._state)}catch(n){console.error("[Crann Agent] Error in onReconnect callback:",n)}})})}notifySubscribers(e){this.subscribers.forEach(t=>{if(!(t.keys&&!t.keys.some(o=>o in e)))try{t.callback(e,this._state)}catch(n){console.error("[Crann Agent] Error in subscriber callback:",n)}})}createActionsProxy(){let e=new Map,t=0;return this.porter.on({rpcResult:n=>{let{callId:o,result:s,error:i,success:a}=n.payload,l=e.get(o);l&&(e.delete(o),a?l.resolve(s):l.reject(new Error(i)))}}),new Proxy({},{get:(n,o)=>async(...s)=>{let i=`${t++}`;return new Promise((a,l)=>{e.set(i,{resolve:a,reject:l}),this.porter.post({action:"rpc",payload:{callId:i,actionName:o,args:s}})})}})}buildDefaultState(){let e={};for(let[t,n]of Object.entries(this.config))t==="name"||t==="version"||t==="actions"||typeof n=="object"&&n!==null&&"default"in n&&(e[t]=n.default);return e}assertNotDisconnected(){if(this._isDisconnected)throw new $(this.config.name,"agent")}};function V(r,e){return new B(r,e)}var te=require("react/jsx-runtime");function ee(r,e={}){let t=null,n=(0,p.createContext)(null);function o(){return t||(t=V(r,{debug:e.debug})),t}function s(){let c=(0,p.useContext)(n),[g,h]=(0,p.useState)(c??t);return(0,p.useEffect)(()=>{g||h(o())},[g]),c??g}function i(){let c=s(),[g,h]=(0,p.useState)(!1);return(0,p.useEffect)(()=>{if(!c)return;c.getInfo()&&h(!0);let y=c.onReady(()=>{h(!0)}),I=c.onDisconnect(()=>{h(!1)}),b=c.onReconnect(()=>{h(!0)});return()=>{y(),I(),b()}},[c]),g}function a(c){let g=s(),h=typeof c=="function",m=h?c:C=>C[c],[y,I]=(0,p.useState)(()=>{if(!g){let C=ue(r);return m(C)}return m(g.getState())}),b=(0,p.useRef)(y);if((0,p.useEffect)(()=>{if(!g)return;let C=g.getState(),M=m(C);return Y(M,b.current)||(b.current=M,I(M)),g.subscribe((z,_)=>{let T=m(_);Y(T,b.current)||(b.current=T,I(T))})},[g,m]),!h){let C=c,M=(0,p.useCallback)(async U=>{g&&await g.setState({[C]:U})},[g,C]);return[y,M]}return y}function l(){let c=s(),g=(0,p.useRef)(null);g.current=c;let h=(0,p.useRef)(null);return h.current||(h.current=new Proxy({},{get:(m,y)=>async(...I)=>{let b=g.current;if(!b)throw new Error(`Cannot call action "${y}" before agent is connected`);return b.actions[y](...I)}})),h.current}return{useCrannState:a,useCrannActions:l,useCrannReady:i,useAgent:s,CrannProvider:({agent:c,children:g})=>{let h=c??o();return(0,te.jsx)(n.Provider,{value:h,children:g})}}}function ue(r){let e={};for(let[t,n]of Object.entries(r))t==="name"||t==="version"||t==="actions"||typeof n=="object"&&n!==null&&"default"in n&&(e[t]=n.default);return e}function Y(r,e){if(r===e)return!0;if(typeof r!="object"||typeof e!="object"||r===null||e===null)return!1;let t=Object.keys(r),n=Object.keys(e);if(t.length!==n.length)return!1;for(let o of t)if(r[o]!==e[o])return!1;return!0}0&&(module.exports={createCrannHooks});
|
|
1
|
+
"use strict";var ne=Object.create;var x=Object.defineProperty;var oe=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var se=Object.getPrototypeOf,ie=Object.prototype.hasOwnProperty;var ae=(r,e)=>{for(var t in e)x(r,t,{get:e[t],enumerable:!0})},G=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of re(e))!ie.call(r,o)&&o!==t&&x(r,o,{get:()=>e[o],enumerable:!(n=oe(e,o))||n.enumerable});return r};var H=(r,e,t)=>(t=r!=null?ne(se(r)):{},G(e||!r||!r.__esModule?x(t,"default",{value:r,enumerable:!0}):t,r)),ce=r=>G(x({},"__esModule",{value:!0}),r);var de={};ae(de,{createCrannHooks:()=>ee});module.exports=ce(de);var m=require("react");var J=H(require("webextension-polyfill"));var w=(a=>(a.ContentScript="contentscript",a.Extension="extension",a.Popup="popup",a.Sidepanel="sidepanel",a.Devtools="devtools",a.Options="options",a.Unknown="unknown",a))(w||{});var u=class extends Error{constructor(t,n,o){super(n);this.type=t;this.details=o;this.name="PorterError"}};function j(){return typeof ServiceWorkerGlobalScope<"u"&&self instanceof ServiceWorkerGlobalScope}var d=class d{constructor(e){this.context=e}static getLevel(){var t,n,o;return((t=d.globalOptions)==null?void 0:t.level)!==void 0?d.globalOptions.level:typeof process<"u"&&(((n=process.env)==null?void 0:n.NODE_ENV)==="production"||((o=process.env)==null?void 0:o.PORTER_ENV)==="production")?1:4}static configure(e){d.globalOptions=e,e.level!==void 0&&(d.level=e.level),e.enabled!==void 0&&(d.enabled=e.enabled)}static getLogger(e){return this.instances.has(e)||this.instances.set(e,new d(e)),this.instances.get(e)}error(e,...t){d.enabled&&d.level>=0&&console.error(`[Porter:${this.context}] ${e}`,...t)}warn(e,...t){d.enabled&&d.level>=1&&console.warn(`[Porter:${this.context}] ${e}`,...t)}info(e,...t){d.enabled&&d.level>=2&&console.info(`[Porter:${this.context}] ${e}`,...t)}debug(e,...t){d.enabled&&d.level>=3&&console.debug(`[Porter:${this.context}] ${e}`,...t)}trace(e,...t){d.enabled&&d.level>=4&&console.trace(`[Porter:${this.context}] ${e}`,...t)}};d.level=d.getLevel(),d.enabled=!1,d.instances=new Map;var y=d;var K=H(require("webextension-polyfill")),W=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 g,h;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,s=n.tabId||-1,i=n.frameId||0;this.logger.debug("Determined context for new agent",{determinedContext:o,tabId:s,frameId:i});let a=Array.from(this.agentsInfo.values()).filter(p=>p.location.context===o&&p.location.tabId===s&&p.location.frameId===i);a.length>0&&this.logger.debug("Adding agent: Found existing similar agent.",{tabAgentsInfo:a});let l=((h=(g=this.getAgentByLocation({context:o,tabId:s,frameId:i}))==null?void 0:g.info)==null?void 0:h.id)||(0,W.v4)();this.logger.debug(`Adding agent with id: ${l}`),this.agents.set(l,e);let f={id:l,location:{context:o,tabId:s,frameId:i},createdAt:Date.now(),lastActiveAt:Date.now()};this.agentsInfo.set(l,f),this.logger.debug(`Constructed agent info: ${JSON.stringify(f)}`),e.onMessage.addListener(p=>this.emit("agentMessage",p,f));let c={port:e,info:f};return e.onDisconnect.addListener(()=>{this.emit("agentDisconnect",f),this.logger.debug("Agent disconnected, removing from manager. ",{agentInfo:f}),this.removeAgent(l)}),this.emit("agentSetup",c),this.logger.debug("Setup complete for adding agent. ",{agentInfo:f}),l}getAgentByLocation(e){let{context:t,tabId:n,frameId:o}=e,s=Array.from(this.agentsInfo.entries()).find(([f,c])=>c.location.context===t&&c.location.tabId===n&&c.location.frameId===o);if(s===void 0)return this.logger.error("No agent found for location. ",{location:e}),null;let i=s[0],a=this.agents.get(i),l=this.agentsInfo.get(i);return!a||!l?(this.logger.error("No agent found for location. ",{location:e}),null):{port:a,info:l}}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 s=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 s&&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 h,p,I,A,C,b,M;let t=e.sender;if(!t)return this.logger.error("Cannot add agent that did not have a sender"),null;let n=K.default.runtime.getManifest(),o=((h=n==null?void 0:n.side_panel)==null?void 0:h.default_path)||"",s=n.options_page||"",i=((p=n.action)==null?void 0:p.default_popup)||"",a=n.devtools_page||"",l=((I=n.chrome_url_overrides)==null?void 0:I.newtab)||"",f=((A=n.chrome_url_overrides)==null?void 0:A.bookmarks)||"",c=((C=n.chrome_url_overrides)==null?void 0:C.history)||"",g={sidepanel:o?o.split("/").pop():"sidepanel.html",options:s?s.split("/").pop():"options.html",popup:i?i.split("/").pop():"popup.html",devtools:a?a.split("/").pop():"devtools.html",newtab:l?l.split("/").pop():"newtab.html",bookmarks:f?f.split("/").pop():"bookmarks.html",history:c?c.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 z=new URL(t.url).pathname.split("/").pop();for(let[_,T]of Object.entries(g))if(z===T)return{context:_,tabId:((b=t.tab)==null?void 0:b.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name};return{context:"unknown",tabId:((M=t.tab)==null?void 0:M.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name}}return{context:"unknown",tabId:0,url:t.url,portName:e.name}}};var L=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 u("invalid-context","Port name not provided");if(!e.name||!e.name.startsWith(this.namespace+":"))throw new u("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 u("invalid-context","Missing context or connection ID. Message was: "+JSON.stringify(t));let o=this.agentOperations.addAgent(e);if(!o)throw new u("invalid-context","Failed to add agent");let s=this.agentOperations.getAgentById(o);s&&this.confirmConnection(s),this.agentOperations.printAgents()}catch(n){this.handleConnectionError(e,n)}}handleConnectionError(e,t){let n=t instanceof u?t:new u("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 u("invalid-port","Agent port is undefined when confirming connection");e.port.postMessage({action:"porter-handshake",payload:{info:e.info,currentConnections:this.agentOperations.getAllAgentsInfo()}})}};var R=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 s=(i=this.agentOperations.getAgentById(o.id))==null?void 0:i.info;if(!s){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",s)}}}async post(e,t){return new Promise((n,o)=>{try{this.logger.debug("Post request received:",{action:e.action,target:t});let s=setTimeout(()=>{let i=new Error("Message posting timed out");this.logger.error("Post timeout:",i),o(i)},5e3);t===void 0?this.broadcastMessage(e):ge(t)?this.postToLocation(e,t):le(t)?this.postToContext(e,t):typeof t=="string"?this.postToId(e,t):this.postToTab(e,t),clearTimeout(s),n()}catch(s){let i=s instanceof Error?s.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 u("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 u("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 u("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 u("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 u("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 s=e[o.message.action];if(s){this.logger.debug("onMessage, calling handler ",{event:o});let{message:i,...a}=o;s(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,...s}=e;n(o,s);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 ge(r){return typeof r=="object"&&r!==null&&"context"in r&&"tabId"in r&&"frameId"in r}function le(r){return typeof r=="string"&&Object.values(w).includes(r)}var v=class v{constructor(e,t){if((t==null?void 0:t.debug)!==void 0&&y.configure({enabled:t.debug}),this.logger=y.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 R(this.agentManager,this.logger),this.connectionManager=new L(this.agentManager,this.namespace,this.logger),this.logger.info(`Constructing Porter with namespace: ${this.namespace}`),!j())throw new u("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)}),J.default.runtime.onConnect.addListener(this.connectionManager.handleConnection.bind(this.connectionManager))}static getInstance(e="porter",t){return v.staticLogger.debug(`Getting instance for namespace: ${e}`),v.instances.has(e)?(t==null?void 0:t.debug)!==void 0&&y.configure({enabled:t.debug}):(v.staticLogger.info(`Creating new instance for namespace: ${e}`),v.instances.set(e,new v(e,t))),v.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)}};v.instances=new Map,v.staticLogger=y.getLogger("SW");var X=v;var Z=H(require("webextension-polyfill"));var k=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.disconnectCallbacks=new Set;this.reconnectCallbacks=new Set;this.connectionId=`${Date.now()}-${Math.random().toString(36).substring(2,9)}`,this.logger=t,this.messageQueue=new k(t)}onDisconnect(e){return this.disconnectCallbacks.add(e),()=>{this.disconnectCallbacks.delete(e)}}onReconnect(e){return this.reconnectCallbacks.add(e),()=>{this.reconnectCallbacks.delete(e)}}emitDisconnect(){this.logger.debug("Emitting disconnect event",{callbackCount:this.disconnectCallbacks.size}),this.disconnectCallbacks.forEach(e=>{try{e()}catch(t){this.logger.error("Error in disconnect callback:",t)}})}emitReconnect(e){this.logger.debug("Emitting reconnect event",{callbackCount:this.reconnectCallbacks.size,info:e}),this.reconnectCallbacks.forEach(t=>{try{t(e)}catch(n){this.logger.error("Error in reconnect callback:",n)}})}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=Z.default.runtime.connect({name:t});let n=new Promise((o,s)=>{var l;let i=setTimeout(()=>s(new u("connection-timeout","Connection timed out waiting for handshake")),this.CONNECTION_TIMEOUT),a=f=>{var c,g;f.action==="porter-handshake"?(this.logger.debug("Received handshake:",f),clearTimeout(i),this.agentInfo=f.payload.info,this.logger.debug("Handshake agent info:",{agentInfo:this.agentInfo}),(c=this.port)==null||c.onMessage.removeListener(a),o()):f.action==="porter-error"&&(clearTimeout(i),(g=this.port)==null||g.onMessage.removeListener(a),this.logger.error("Error:",f),s(new u(f.payload.type,f.payload.message,f.payload.details)))};(l=this.port)==null||l.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{let o={...t};n&&(o.target=n),this.port.postMessage(o),this.logger.debug("Successfully resent queued message:",{message:o})}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.emitDisconnect(),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.reconnectTimer=null),this.logger.info("Reconnection successful",{attempts:this.reconnectAttemptCount,queuedMessages:this.messageQueue.isEmpty()?0:"some"}),this.agentInfo&&this.emitReconnect(this.agentInfo)}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 O=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(s=>s(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 u("message-failed","Failed to post message",{originalError:o,message:t,target:n})}}};var S=class S{constructor(e={}){let t=e.namespace??"porter",n=e.agentContext??this.determineContext();e.debug!==void 0&&y.configure({enabled:e.debug}),this.logger=y.getLogger("Agent"),this.connectionManager=new N(t,this.logger),this.messageHandler=new O(this.logger),this.connectionManager.onReconnect(o=>{this.logger.info("Reconnected, re-wiring port listeners",{info:o}),this.setupPortListeners()}),this.logger.info("Initializing with options: ",{options:e,context:n}),this.initializeConnection()}static getInstance(e={}){return!S.instance||S.instance.connectionManager.getNamespace()!==e.namespace?S.instance=new S(e):e.debug!==void 0&&y.configure({enabled:e.debug}),S.instance}async initializeConnection(){await this.connectionManager.initializeConnection(),this.setupPortListeners()}setupPortListeners(){let e=this.connectionManager.getPort();e?(this.logger.debug("Setting up port listeners"),e.onMessage.addListener(t=>this.messageHandler.handleMessage(e,t)),e.onDisconnect.addListener(t=>this.connectionManager.handleDisconnect(t))):this.logger.warn("Cannot setup port listeners: no port available")}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}onDisconnect(e){return this.connectionManager.onDisconnect(e)}onReconnect(e){return this.connectionManager.onReconnect(e)}};S.instance=null;var F=S;function q(r){let e=F.getInstance(r);return{type:"agent",post:e.post.bind(e),onMessage:e.onMessage.bind(e),on:e.on.bind(e),getAgentInfo:e.getAgentInfo.bind(e),onDisconnect:e.onDisconnect.bind(e),onReconnect:e.onReconnect.bind(e)}}var P=require("react");var Q=class extends Error{constructor(e){super(e),this.name="CrannError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}};var $=class extends Q{constructor(t,n){super(`${n==="store"?"Store":"Agent"} "${t}" has been ${n==="store"?"destroyed":"disconnected"} and cannot be used.`);this.storeName=t;this.entity=n;this.name="LifecycleError"}};var B=class{constructor(e,t={}){this._agentInfo=null;this._isConnected=!1;this._isDisconnected=!1;this.subscribers=new Set;this.readyCallbacks=new Set;this.disconnectCallbacks=new Set;this.reconnectCallbacks=new Set;this.config=e,this.options=t,this._state=this.buildDefaultState(),this.readyPromise=new Promise(n=>{this.readyResolve=n}),this.porter=q({namespace:e.name,debug:t.debug??!1}),this.setupMessageHandlers(),this.actionsProxy=this.createActionsProxy()}ready(){return this.assertNotDisconnected(),this.readyPromise}onReady(e){return this.assertNotDisconnected(),this._isConnected&&setTimeout(()=>e(this._state),0),this.readyCallbacks.add(e),()=>{this.readyCallbacks.delete(e)}}getState(){return this.assertNotDisconnected(),{...this._state}}get state(){return this.getState()}async setState(e){this.assertNotDisconnected(),this._state={...this._state,...e},this.porter.post({action:"setState",payload:{state:e}})}subscribe(e,t){this.assertNotDisconnected();let n,o;typeof e=="function"?o=e:(n=e,o=t);let s={keys:n,callback:o};return this.subscribers.add(s),()=>{this.subscribers.delete(s)}}get actions(){return this.assertNotDisconnected(),this.actionsProxy}getInfo(){return this._agentInfo?{id:this._agentInfo.id,tabId:this._agentInfo.location.tabId,frameId:this._agentInfo.location.frameId,context:this._agentInfo.location.context}:null}onDisconnect(e){return this.assertNotDisconnected(),this.disconnectCallbacks.add(e),()=>{this.disconnectCallbacks.delete(e)}}onReconnect(e){return this.assertNotDisconnected(),this.reconnectCallbacks.add(e),()=>{this.reconnectCallbacks.delete(e)}}disconnect(){this._isDisconnected||(this._isDisconnected=!0,this._isConnected=!1,this.subscribers.clear(),this.readyCallbacks.clear(),this.disconnectCallbacks.clear(),this.reconnectCallbacks.clear())}setupMessageHandlers(){this.porter.on({initialState:e=>{let{state:t,info:n}=e.payload;this._state=t,this._agentInfo=n,this._isConnected=!0,this.readyResolve(this._state),this.readyCallbacks.forEach(o=>{try{o(this._state)}catch(s){console.error("[Crann Agent] Error in onReady callback:",s)}}),this.notifySubscribers(t)},stateUpdate:e=>{let{state:t}=e.payload;this._state={...this._state,...t},this.notifySubscribers(t)},rpcResult:e=>{}}),this.porter.onDisconnect(()=>{this._isConnected=!1,this.disconnectCallbacks.forEach(e=>{try{e()}catch(t){console.error("[Crann Agent] Error in onDisconnect callback:",t)}})}),this.porter.onReconnect(e=>{this._agentInfo=e,this._isConnected=!0,this.reconnectCallbacks.forEach(t=>{try{t(this._state)}catch(n){console.error("[Crann Agent] Error in onReconnect callback:",n)}})})}notifySubscribers(e){this.subscribers.forEach(t=>{if(!(t.keys&&!t.keys.some(o=>o in e)))try{t.callback(e,this._state)}catch(n){console.error("[Crann Agent] Error in subscriber callback:",n)}})}createActionsProxy(){let e=new Map,t=0;return this.porter.on({rpcResult:n=>{let{callId:o,result:s,error:i,success:a}=n.payload,l=e.get(o);l&&(e.delete(o),a?l.resolve(s):l.reject(new Error(i)))}}),new Proxy({},{get:(n,o)=>async(...s)=>{let i=`${t++}`;return new Promise((a,l)=>{e.set(i,{resolve:a,reject:l}),this.porter.post({action:"rpc",payload:{callId:i,actionName:o,args:s}})})}})}buildDefaultState(){let e={};for(let[t,n]of Object.entries(this.config))t==="name"||t==="version"||t==="actions"||typeof n=="object"&&n!==null&&"default"in n&&(e[t]=n.default);return e}assertNotDisconnected(){if(this._isDisconnected)throw new $(this.config.name,"agent")}};function V(r,e){return new B(r,e)}var te=require("react/jsx-runtime");function ee(r,e={}){let t=null,n=(0,m.createContext)(null);function o(){return t||(t=V(r,{debug:e.debug})),t}function s(){let c=(0,m.useContext)(n),[g,h]=(0,m.useState)(c??t);return(0,m.useEffect)(()=>{g||h(o())},[g]),c??g}function i(){let c=s(),[g,h]=(0,m.useState)(!1);return(0,m.useEffect)(()=>{if(!c)return;c.getInfo()&&h(!0);let I=c.onReady(()=>{h(!0)}),A=c.onDisconnect(()=>{h(!1)}),C=c.onReconnect(()=>{h(!0)});return()=>{I(),A(),C()}},[c]),g}function a(c){let g=s(),h=typeof c=="function",p=h?c:b=>b[c],[I,A]=(0,m.useState)(()=>{if(!g){let b=ue(r);return p(b)}return p(g.getState())}),C=(0,m.useRef)(I);if((0,m.useEffect)(()=>{if(!g)return;let b=g.getState(),M=p(b);return Y(M,C.current)||(C.current=M,A(M)),g.subscribe((z,_)=>{let T=p(_);Y(T,C.current)||(C.current=T,A(T))})},[g,p]),!h){let b=c,M=(0,m.useCallback)(async U=>{g&&await g.setState({[b]:U})},[g,b]);return[I,M]}return I}function l(){let c=s(),g=(0,m.useRef)(null);g.current=c;let h=(0,m.useRef)({}),p=(0,m.useRef)(null);return p.current||(p.current=new Proxy({},{get:(I,A)=>(h.current[A]||(h.current[A]=async(...C)=>{let b=g.current;if(!b)throw new Error(`Cannot call action "${A}" before agent is connected`);return b.actions[A](...C)}),h.current[A])})),p.current}return{useCrannState:a,useCrannActions:l,useCrannReady:i,useAgent:s,CrannProvider:({agent:c,children:g})=>{let h=c??o();return(0,te.jsx)(n.Provider,{value:h,children:g})}}}function ue(r){let e={};for(let[t,n]of Object.entries(r))t==="name"||t==="version"||t==="actions"||typeof n=="object"&&n!==null&&"default"in n&&(e[t]=n.default);return e}function Y(r,e){if(r===e)return!0;if(typeof r!="object"||typeof e!="object"||r===null||e===null)return!1;let t=Object.keys(r),n=Object.keys(e);if(t.length!==n.length)return!1;for(let o of t)if(r[o]!==e[o])return!1;return!0}0&&(module.exports={createCrannHooks});
|
|
2
2
|
//# sourceMappingURL=react.js.map
|