crann 2.0.2 → 2.0.3

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/index.js CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";var Oe=Object.create;var B=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var Ne=Object.getOwnPropertyNames;var qe=Object.getPrototypeOf,Ue=Object.prototype.hasOwnProperty;var Be=(i,e)=>{for(var t in e)B(i,t,{get:e[t],enumerable:!0})},Ce=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Ne(e))!Ue.call(i,o)&&o!==t&&B(i,o,{get:()=>e[o],enumerable:!(n=be(e,o))||n.enumerable});return i};var X=(i,e,t)=>(t=i!=null?Oe(qe(i)):{},Ce(e||!i||!i.__esModule?B(t,"default",{value:i,enumerable:!0}):t,i)),Fe=i=>Ce(B({},"__esModule",{value:!0}),i),ge=(i,e,t,n)=>{for(var o=n>1?void 0:n?be(e,t):e,r=i.length-1,a;r>=0;r--)(a=i[r])&&(o=(n?a(e,t,o):a(o))||o);return n&&o&&B(e,t,o),o};var Qe={};Be(Qe,{Crann:()=>G,Partition:()=>F,Persistence:()=>ve,connect:()=>ae,connected:()=>Ee,create:()=>Pe,createConfig:()=>Le,createCrannStateHook:()=>De});module.exports=Fe(Qe);var j=X(require("webextension-polyfill"));var F={Instance:"instance",Service:"service"},ve={Session:"session",Local:"local",None:"none"},$=i=>!("handler"in i),J=i=>"handler"in i;var Te=X(require("webextension-polyfill"));var K=(g=>(g.ContentScript="contentscript",g.Extension="extension",g.Popup="popup",g.Sidepanel="sidepanel",g.Devtools="devtools",g.Options="options",g.Unknown="unknown",g))(K||{});var C=class extends Error{constructor(t,n,o){super(n);this.type=t;this.details=o;this.name="PorterError"}};function ye(){return typeof ServiceWorkerGlobalScope<"u"&&self instanceof ServiceWorkerGlobalScope}var y=class y{constructor(e){this.context=e}static getLevel(){var t,n,o;return((t=y.globalOptions)==null?void 0:t.level)!==void 0?y.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){y.globalOptions=e,e.level!==void 0&&(y.level=e.level),e.enabled!==void 0&&(y.enabled=e.enabled)}static getLogger(e){return this.instances.has(e)||this.instances.set(e,new y(e)),this.instances.get(e)}error(e,...t){y.enabled&&y.level>=0&&console.error(`[Porter:${this.context}] ${e}`,...t)}warn(e,...t){y.enabled&&y.level>=1&&console.warn(`[Porter:${this.context}] ${e}`,...t)}info(e,...t){y.enabled&&y.level>=2&&console.info(`[Porter:${this.context}] ${e}`,...t)}debug(e,...t){y.enabled&&y.level>=3&&console.debug(`[Porter:${this.context}] ${e}`,...t)}trace(e,...t){y.enabled&&y.level>=4&&console.trace(`[Porter:${this.context}] ${e}`,...t)}};y.level=y.getLevel(),y.enabled=!1,y.instances=new Map;var P=y;var Se=X(require("webextension-polyfill")),Ae=require("uuid");var _=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 u,p;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,a=n.frameId||0;this.logger.debug("Determined context for new agent",{determinedContext:o,tabId:r,frameId:a});let g=Array.from(this.agentsInfo.values()).filter(f=>f.location.context===o&&f.location.tabId===r&&f.location.frameId===a);g.length>0&&this.logger.debug("Adding agent: Found existing similar agent.",{tabAgentsInfo:g});let s=((p=(u=this.getAgentByLocation({context:o,tabId:r,frameId:a}))==null?void 0:u.info)==null?void 0:p.id)||(0,Ae.v4)();this.logger.debug(`Adding agent with id: ${s}`),this.agents.set(s,e);let c={id:s,location:{context:o,tabId:r,frameId:a},createdAt:Date.now(),lastActiveAt:Date.now()};this.agentsInfo.set(s,c),this.logger.debug(`Constructed agent info: ${JSON.stringify(c)}`),e.onMessage.addListener(f=>this.emit("agentMessage",f,c));let d={port:e,info:c};return e.onDisconnect.addListener(()=>{this.emit("agentDisconnect",c),this.logger.debug("Agent disconnected, removing from manager. ",{agentInfo:c}),this.removeAgent(s)}),this.emit("agentSetup",d),this.logger.debug("Setup complete for adding agent. ",{agentInfo:c}),s}getAgentByLocation(e){let{context:t,tabId:n,frameId:o}=e,r=Array.from(this.agentsInfo.entries()).find(([c,d])=>d.location.context===t&&d.location.tabId===n&&d.location.frameId===o);if(r===void 0)return this.logger.error("No agent found for location. ",{location:e}),null;let a=r[0],g=this.agents.get(a),s=this.agentsInfo.get(a);return!g||!s?(this.logger.error("No agent found for location. ",{location:e}),null):{port:g,info:s}}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,a=e.tabId?o.location.tabId===e.tabId:!0,g=e.frameId?o.location.frameId===e.frameId:!0;return r&&a&&g}).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 p,f,b,v,h,M,S;let t=e.sender;if(!t)return this.logger.error("Cannot add agent that did not have a sender"),null;let n=Se.default.runtime.getManifest(),o=((p=n==null?void 0:n.side_panel)==null?void 0:p.default_path)||"",r=n.options_page||"",a=((f=n.action)==null?void 0:f.default_popup)||"",g=n.devtools_page||"",s=((b=n.chrome_url_overrides)==null?void 0:b.newtab)||"",c=((v=n.chrome_url_overrides)==null?void 0:v.bookmarks)||"",d=((h=n.chrome_url_overrides)==null?void 0:h.history)||"",u={sidepanel:o?o.split("/").pop():"sidepanel.html",options:r?r.split("/").pop():"options.html",popup:a?a.split("/").pop():"popup.html",devtools:g?g.split("/").pop():"devtools.html",newtab:s?s.split("/").pop():"newtab.html",bookmarks:c?c.split("/").pop():"bookmarks.html",history:d?d.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 R=new URL(t.url).pathname.split("/").pop();for(let[O,he]of Object.entries(u))if(R===he)return{context:O,tabId:((M=t.tab)==null?void 0:M.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name};return{context:"unknown",tabId:((S=t.tab)==null?void 0:S.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name}}return{context:"unknown",tabId:0,url:t.url,portName:e.name}}};var Y=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 C("invalid-context","Port name not provided");if(!e.name||!e.name.startsWith(this.namespace+":"))throw new C("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 C("invalid-context","Missing context or connection ID. Message was: "+JSON.stringify(t));let o=this.agentOperations.addAgent(e);if(!o)throw new C("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 C?t:new C("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 C("invalid-port","Agent port is undefined when confirming connection");e.port.postMessage({action:"porter-handshake",payload:{info:e.info,currentConnections:this.agentOperations.getAllAgentsInfo()}})}};var ee=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 a;if(!o||!o.id)return;let r=(a=this.agentOperations.getAgentById(o.id))==null?void 0:a.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 a=new Error("Message posting timed out");this.logger.error("Post timeout:",a),o(a)},5e3);t===void 0?this.broadcastMessage(e):$e(t)?this.postToLocation(e,t):Ke(t)?this.postToContext(e,t):typeof t=="string"?this.postToId(e,t):this.postToTab(e,t),clearTimeout(r),n()}catch(r){let a=r instanceof Error?r.message:"Unknown error";this.logger.error("Failed to post message:",a),o(new Error(`Failed to post message: ${a}`))}})}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 C("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 C("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 C("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 C("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 C("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:a,...g}=o;r(a,g)}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 $e(i){return typeof i=="object"&&i!==null&&"context"in i&&"tabId"in i&&"frameId"in i}function Ke(i){return typeof i=="string"&&Object.values(K).includes(i)}var D=class D{constructor(e,t){if((t==null?void 0:t.debug)!==void 0&&P.configure({enabled:t.debug}),this.logger=P.getLogger("SW"),this.namespace=e||"porter",e||this.logger.error('No namespace provided, defaulting to "porter"'),this.agentManager=new _(this.logger),this.messageHandler=new ee(this.agentManager,this.logger),this.connectionManager=new Y(this.agentManager,this.namespace,this.logger),this.logger.info(`Constructing Porter with namespace: ${this.namespace}`),!ye())throw new C("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)}),Te.default.runtime.onConnect.addListener(this.connectionManager.handleConnection.bind(this.connectionManager))}static getInstance(e="porter",t){return D.staticLogger.debug(`Getting instance for namespace: ${e}`),D.instances.has(e)?(t==null?void 0:t.debug)!==void 0&&P.configure({enabled:t.debug}):(D.staticLogger.info(`Creating new instance for namespace: ${e}`),D.instances.set(e,new D(e,t))),D.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)}};D.instances=new Map,D.staticLogger=P.getLogger("SW");var ce=D;function H(i="porter",e){let t=ce.getInstance(i,e);return{type:"source",post:t.post.bind(t),onMessage:t.onMessage.bind(t),on:t.on.bind(t),onConnect:t.onConnect.bind(t),onDisconnect:t.onDisconnect.bind(t),onMessagesSet:t.onMessagesSet.bind(t),getAgentById:t.getAgentById.bind(t),getAgentByLocation:t.getAgentByLocation.bind(t),queryAgents:t.queryAgents.bind(t)}}var Ie=X(require("webextension-polyfill"));var te=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 ne=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 te(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=Ie.default.runtime.connect({name:t});let n=new Promise((o,r)=>{var s;let a=setTimeout(()=>r(new C("connection-timeout","Connection timed out waiting for handshake")),this.CONNECTION_TIMEOUT),g=c=>{var d,u;c.action==="porter-handshake"?(this.logger.debug("Received handshake:",c),clearTimeout(a),this.agentInfo=c.payload.info,this.logger.debug("Handshake agent info:",{agentInfo:this.agentInfo}),(d=this.port)==null||d.onMessage.removeListener(g),o()):c.action==="porter-error"&&(clearTimeout(a),(u=this.port)==null||u.onMessage.removeListener(g),this.logger.error("Error:",c),r(new C(c.payload.type,c.payload.message,c.payload.details)))};(s=this.port)==null||s.onMessage.addListener(g)});(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 oe=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 C("message-failed","Failed to post message",{originalError:o,message:t,target:n})}}};var k=class k{constructor(e={}){let t=e.namespace??"porter",n=e.agentContext??this.determineContext();e.debug!==void 0&&P.configure({enabled:e.debug}),this.logger=P.getLogger("Agent"),this.connectionManager=new ne(t,this.logger),this.messageHandler=new oe(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!k.instance||k.instance.connectionManager.getNamespace()!==e.namespace?k.instance=new k(e):e.debug!==void 0&&P.configure({enabled:e.debug}),k.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)}};k.instance=null;var le=k;function re(i){let e=le.getInstance(i);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 z=require("react");function ie(i,e){if(i===e)return!0;if(i==null||typeof i!="object"||e==null||typeof e!="object")return!1;let t=Object.keys(i),n=Object.keys(e);if(t.length!==n.length)return!1;t.sort(),n.sort();for(let o=0;o<t.length;o++){let r=t[o];if(r!==n[o]||!ie(i[r],e[r]))return!1}return!0}var Q=class Q{static setDebug(e){Q._debug=e}static isDebugEnabled(){return Q._debug}};Q._debug=!1;var V=Q;function Me(){return V.isDebugEnabled()}function de(i,e,t){let n=t.value;return t.value=function(...o){var r;if(Me()){let a=new Error().stack,s=(r=((a==null?void 0:a.split(`
2
- `))||[])[3])==null?void 0:r.match(/at\s+(\S+)\s+/),c=s?s[1]:"unknown",d=o.length>1?o[1]:void 0,u={source:c,timestamp:Date.now(),instanceKey:o[0],changes:d};console.log("Crann State Change:",u)}return n.apply(this,o)},t}var A=class A{constructor(e){this.tag=null;this.context=e}static setDebug(e){A.debug=e}static setPrefix(e){A.prefix=e}setTag(e){this.tag=e}withTag(e){let t=new A(this.context);return t.setTag(e),t}getFullContext(){return this.tag?`${this.context}:${this.tag}`:this.context}createLogMethods(){let e=this.getFullContext(),t=`%c${A.prefix}%c [%c${e}%c]`,n="color: #3fcbff; font-weight: bold",o="color: #d58cff; font-weight: bold",r="";return A.debug?{debug:console.log.bind(console,t,n,r,o,r),log:console.log.bind(console,t,n,r,o,r),info:console.info.bind(console,t,n,r,o,r),warn:console.warn.bind(console,t,n,r,o,r),error:console.error.bind(console,t,n,r,o,r)}:{debug:A.noOp,log:A.noOp,info:A.noOp,warn:A.noOp,error:A.noOp}}get debug(){return this.createLogMethods().debug}get log(){return this.createLogMethods().log}get info(){return this.createLogMethods().info}get warn(){return this.createLogMethods().warn}get error(){return this.createLogMethods().error}static forContext(e,t){let n=new A(e);return t&&n.setTag(t),n}};A.debug=!1,A.prefix="CrannLogger",A.noOp=function(){};var x=A;function T(i,e={terse:!0}){let n=(o=>{let r=String(o);return r.length>=4?r.slice(-4):r.padStart(4,"0")})(i.location.tabId);return e!=null&&e.terse?`${n}:${i.location.frameId}`:`${i.location.context}:${n}:${i.location.frameId}`}function xe(i,e,t,n,o){var d,u;let r=new Map,a=new Map,g=(d=i.context)!=null&&d.isServiceWorker?"Core":"Agent",s=x.forContext(`${g}:RPC`);return(u=i.context)!=null&&u.agentInfo&&s.setTag(T(i.context.agentInfo)),i.addEventListener("message",p=>{s.debug("Message received:",p);let[f,b]=p.data;if("call"in b&&"args"in b.call){s.debug("Processing call message:",b);let v=b.call,{id:h,args:M,target:S}=v,q=t[h];if(!q){i.postMessage([f,{error:{id:h,error:"Action not found",target:S}}]);return}try{if(q.validate&&q.validate(...M),!S){i.postMessage([f,{error:{id:h,error:"No target provided for action call",target:S}}]);return}let R=e();s.debug("Executing action with most current state:",R),Promise.resolve(q.handler(R,n,S,...M)).then(O=>{s.debug("Action handler result:",{result:O,target:S}),i.postMessage([f,{result:{id:h,result:O,target:S}}])},O=>{i.postMessage([f,{error:{id:h,error:O.message,target:S}}])})}catch(R){R instanceof Error?i.postMessage([f,{error:{id:h,error:R.message,target:S}}]):i.postMessage([f,{error:{id:h,error:"Unknown error occurred",target:S}}])}}else if("result"in b){let v=b.result,h=r.get(f);h&&(h(v.result),r.delete(f))}else if("error"in b){let v=b.error,h=r.get(f);h&&(h(Promise.reject(new Error(v.error))),r.delete(f))}else if("release"in b){let v=b.release,h=a.get(v.id);h&&(h.clear(),a.delete(v.id))}}),new Proxy({},{get(p,f){return(...b)=>{let v=Math.random();return new Promise((h,M)=>{r.set(v,S=>{S instanceof Promise?S.then(h,M):h(S)}),i.postMessage([v,{call:{id:f,args:b}}])})}}})}function se(i,e,t,n){let o=t||H("crann"),r=o.type!=="agent",a=x.forContext(r?"Core:RPC":"Agent:RPC"),g={postMessage:(s,c)=>{if(r){a.debug("Posting message from service worker:",{message:s,transferables:c});let[,d]=s,u=He(d);if(!u){a.warn("No target specified for RPC response in service worker");return}o.post({action:"rpc",payload:{message:s,transferables:c||[]}},u)}else{let d=o.getAgentInfo();if(!d){a.warn("No agent info found for posting message",{agentInfo:d});return}let u=T(d),[,p]=s;"call"in p&&(p.call.target=d==null?void 0:d.location),a.withTag(u).debug("Sending RPC message from agent:",{rpcPayload:p,message:s}),o.post({action:"rpc",payload:{message:s,transferables:c||[]}})}},addEventListener:(s,c)=>{o.on({rpc:(d,u)=>{try{if(!u)a.debug("RPC message received:",{message:d,event:s});else{let h=T(u);a.withTag(h).debug("RPC message received:",{message:d,event:s})}let{payload:p}=d,{message:f,transferables:b=[]}=p,v=new MessageEvent("message",{data:f,ports:b.filter(h=>h instanceof MessagePort)||[]});c(v)}catch(p){a.error("Failed to parse RPC message payload:",p)}}})},removeEventListener:()=>{},context:{isServiceWorker:r,agentInfo:r?void 0:o.getAgentInfo()}};return xe(g,i,e,n)}function He(i){if("result"in i)return i.result.target;if("error"in i)return i.error.target;if("call"in i)return i.call.target;if("release"in i)return i.release.target}var L=class L{constructor(e,t){this.config=e;this.instances=new Map;this.stateChangeListeners=[];this.instanceReadyListeners=[];this.storagePrefix="crann_";this.porter=H("crann",{debug:!1});t!=null&&t.debug&&(V.setDebug(!0),x.setDebug(!0)),this.storagePrefix=(t==null?void 0:t.storagePrefix)??this.storagePrefix,this.logger=x.forContext("Core"),this.logger.log("Constructing Crann with new logger"),this.defaultInstanceState=this.initializeInstanceDefault(),this.defaultServiceState=this.serviceState=this.initializeServiceDefault(),this.hydrate(),this.logger.log("Crann constructed, setting initial message handlers"),this.porter.on({setState:(s,c)=>{if(!c){this.logger.warn("setState message heard from unknown agent");return}let d=T(c);this.logger.withTag(d).log("Setting state:",s),this.set(s.payload.state,c.id)}});let n=new Set;this.porter.onMessagesSet(s=>{if(!s){this.logger.error("Messages set but no agent info.",{info:s});return}let c=T(s);if(this.logger.withTag(c).log("onMessagesSet received for agent:",{id:s.id,context:s.location.context,tabId:s.location.tabId,frameId:s.location.frameId,alreadyInitialized:n.has(s.id)}),n.has(s.id)){this.logger.withTag(c).log("Already sent initialState to agent, skipping:",s.id);return}n.add(s.id),this.logger.withTag(c).log("Messages set received. Sending initial state.",{info:s});let d=this.get(s.id);this.porter.post({action:"initialState",payload:{state:d,info:s}},s.location),this.notifyInstanceReady(s.id,s)}),this.porter.onConnect(s=>{if(!s){this.logger.error("Agent connected but no agent info.",{info:s});return}let c=T(s);this.logger.withTag(c).log("Agent connected",{info:s}),this.addInstance(s.id,c),this.porter.onDisconnect(d=>{this.logger.withTag(T(d)).log("Agent disconnect heard. Connection type, context and location:",{info:d}),this.removeInstance(d.id)})});let r=(s,c)=>c!==void 0?this.set(s,c):this.set(s),a=this.extractActions(e),g=()=>{let s=this.get();return this.logger.log("State getter called, returning current state:",s),s};this.rpcEndpoint=se(g,a,this.porter,r)}static getInstance(e,t){return L.instance?t!=null&&t.debug&&x.forContext("Core").log("Instance requested and already existed, returning"):L.instance=new L(e,t),L.instance}async addInstance(e,t){if(this.instances.has(e))this.logger.withTag(t).log("Instance was already registered, ignoring request from key");else{this.logger.withTag(t).log("Adding instance from agent key");let n={...this.defaultInstanceState};this.instances.set(e,n)}}async removeInstance(e){this.instances.has(e)?(this.logger.withTag(e).log("Remove instance requested"),this.instances.delete(e)):this.logger.withTag(e).log("Remove instance requested but it did not exist!")}async setServiceState(e){this.logger.log("Request to set service state with update:",e),this.logger.log("Existing service state was ",this.serviceState);let t={...this.serviceState,...e};ie(this.serviceState,t)?this.logger.log("New state seems to be the same as existing, skipping"):(this.logger.log("Confirmed new state was different than existing so proceeding to persist then notify all connected instances."),this.serviceState=t,await this.persist(e),this.notify(e))}async setInstanceState(e,t){this.logger.withTag(e).log("Request to update instance state, update:",t);let n=this.instances.get(e)||this.defaultInstanceState,o={...n,...t};ie(n,o)?this.logger.withTag(e).log("Instance state update is not different, skipping update."):(this.logger.withTag(e).log("Instance state update is different, updating and notifying."),this.instances.set(e,o),this.notify(t,e))}async persist(e){this.logger.log("Persisting state");let t=!1;for(let n in e||this.serviceState){let r=this.config[n].persist||"none",a=e?e[n]:this.serviceState[n];switch(r){case"session":await j.default.storage.session.set({[this.storagePrefix+n]:a}),t=!0;break;case"local":await j.default.storage.local.set({[this.storagePrefix+n]:a}),t=!0;break;default:break}}t?this.logger.log("State was persisted"):this.logger.log("Nothing to persist")}async clear(){this.logger.log("Clearing state"),this.serviceState=this.defaultServiceState,this.instances.forEach((e,t)=>{this.instances.set(t,this.defaultInstanceState)}),await this.persist(),this.notify({})}subscribe(e){this.logger.log("Subscribing to state"),this.stateChangeListeners.push(e)}notify(e,t){let n=t?this.porter.getAgentById(t):void 0,o=t?this.get(t):this.get();this.stateChangeListeners.length>0&&(this.logger.log("Notifying state change listeners in source"),this.stateChangeListeners.forEach(r=>{r(o,e,n==null?void 0:n.info)})),t&&(n!=null&&n.info.location)?(this.logger.withTag(t).log("Notifying of state change."),this.porter.post({action:"stateUpdate",payload:{state:e}},n.info.location)):(this.logger.log("Notifying everyone"),this.instances.forEach((r,a)=>{this.porter.post({action:"stateUpdate",payload:{state:e}},a)}))}get(e){return e?{...this.serviceState,...this.instances.get(e)}:{...this.serviceState}}findInstance(e){let t=this.porter.getAgentByLocation(e);if(!t)return this.logger.log("Could not find agent for location:",{location:e}),null;for(let[n,o]of this.instances)if(n===t.info.id)return this.logger.log("Found instance for key:",n),n;return this.logger.log("Could not find instance for context and location:",{location:e}),null}queryAgents(e){return this.porter.queryAgents(e)}async set(e,t){let n={},o={};for(let r in e){let a=this.config[r];if(ze(a)){if(a.partition==="instance"){let g=r,s=e;n[g]=s[g]}else if(!a.partition||a.partition===F.Service){let g=r,s=e;o[g]=s[g]}}}t&&Object.keys(n).length>0&&(this.logger.withTag(t).log("Setting instance state:",n),this.setInstanceState(t,n)),Object.keys(o).length>0&&(this.logger.log("Setting service state:",o),this.setServiceState(o))}async hydrate(){this.logger.log("Hydrating state from storage.");let e=await j.default.storage.local.get(null),t=await j.default.storage.session.get(null),n={...e,...t};this.logger.log("Storage data is:",{local:e,session:t,combined:n});let o={},r=!1;for(let a in n){let g=this.removePrefix(a);if(this.logger.log(`Checking storage key ${a} -> ${g}`),this.config.hasOwnProperty(g)){let s=n[a];this.logger.log(`Found storage value for ${g}:`,s),o[g]=s,r=!0}}r?this.logger.log("Hydrated some items."):this.logger.log("No items found in storage."),this.serviceState={...this.defaultServiceState,...o}}removePrefix(e){return e.startsWith(this.storagePrefix)?e.replace(this.storagePrefix,""):e}initializeInstanceDefault(){let e={};return Object.keys(this.config).forEach(t=>{let n=this.config[t];$(n)&&n.partition==="instance"&&(e[t]=n.default)}),e}initializeServiceDefault(){this.logger.log("Initializing service default state"),this.logger.log("Config is:",this.config);let e={};return Object.keys(this.config).forEach(t=>{let n=this.config[t];this.logger.log("Item is:",n),$(n)&&(!n.partition||n.partition===F.Service)&&(e[t]=n.default,this.logger.log("Setting service state for key:",t,"to",n.default))}),this.logger.log("Final service state is:",e),e}subscribeToInstanceReady(e){return this.logger.log("Subscribing to instance ready events"),this.instanceReadyListeners.push(e),this.instances.forEach((t,n)=>{let o=this.porter.getAgentById(n);o!=null&&o.info&&e(n,o.info)}),()=>{this.logger.log("Unsubscribing from instance ready events");let t=this.instanceReadyListeners.indexOf(e);t!==-1&&this.instanceReadyListeners.splice(t,1)}}notifyInstanceReady(e,t){if(this.instanceReadyListeners.length>0){let n=T(t);this.logger.withTag(n).log("Notifying instance ready listeners"),this.instanceReadyListeners.forEach(o=>{o(e,t)})}}extractActions(e){return Object.entries(e).filter(([t,n])=>J(n)).reduce((t,[n,o])=>{let r=o;return{...t,[n]:r}},{})}};L.instance=null,ge([de],L.prototype,"setServiceState",1),ge([de],L.prototype,"setInstanceState",1);var G=L;function Pe(i,e){let t=G.getInstance(i,e);return{get:t.get.bind(t),set:t.set.bind(t),subscribe:t.subscribe.bind(t),onInstanceReady:t.subscribeToInstanceReady.bind(t),findInstance:t.findInstance.bind(t),queryAgents:t.queryAgents.bind(t),clear:t.clear.bind(t)}}function ze(i){return i&&typeof i=="object"&&"default"in i}var E={connected:!1},N=null,ue=new Set,fe=new Set;function ae(i,e){let t=(e==null?void 0:e.debug)||!1,n=e==null?void 0:e.context;t&&x.setDebug(!0);let o=x.forContext("Agent"),r,a="unset",g=new Set;if(o.log("Initializing Crann Agent"+(n?` with context: ${n}`:"")),N&&E.connected)return o.log("We had an instance already and it's connected, returning"),o.log("Connect, calling onReady callback"),setTimeout(()=>{g.forEach(l=>l(E))},0),N;N&&!E.connected&&(o.log("We had an instance but it's disconnected, creating new connection"),N=null),o.log("No existing instance, creating a new one");let s=re({namespace:"crann",debug:!1});o.log("Porter connection created"),s.onDisconnect(()=>{o.log("Porter connection lost, updating connection status"),E={connected:!1},ue.forEach(l=>{try{l()}catch(m){o.error("Error in disconnect callback:",m)}}),g.forEach(l=>{try{l(E)}catch(m){o.error("Error in onReady callback during disconnect:",m)}})}),s.onReconnect(l=>{o.log("Porter reconnected, updating connection status",l),E={connected:!0,agent:l},r=l,a=T(l),o.setTag(a),fe.forEach(m=>{try{m(l)}catch(w){o.error("Error in reconnect callback:",w)}}),g.forEach(m=>{try{m(E)}catch(w){o.error("Error in onReady callback during reconnect:",w)}})});let c=Object.entries(i).filter(([l,m])=>J(m)).reduce((l,[m,w])=>{let U=w;return{...l,[m]:{type:"action",handler:U.handler,validate:U.validate}}},{}),d=se(()=>we(i),c,s),u=!1;s.on({initialState:l=>{if(o.log("initialState received",{alreadyReceived:u,payload:l.payload}),u){o.log("Ignoring duplicate initialState message");return}u=!0,p=l.payload.state,r=l.payload.info,a=T(r),E={connected:!0,agent:r},o.setTag(a),o.log(`Initial state received and ${b.size} listeners notified`,{message:l}),g.forEach(m=>{o.log("Calling onReady callbacks"),m(E)}),b.forEach(m=>{m.callback(p)})},stateUpdate:l=>{f=l.payload.state,p={...p,...f},o.log("State updated:",{message:l,changes:f,_state:p}),f&&b.forEach(m=>{(m.keys===void 0||m.keys.some(U=>U in f))&&m.callback(f)})}}),o.log("Porter connected. Setting up state and listeners");let p=we(i),f=null,b=new Set;o.log("Completed setup, returning instance");let v=()=>p,h=l=>{o.log("Calling post with setState",l),s.post({action:"setState",payload:{state:l}})},M=(l,m)=>{let w={keys:m,callback:l};return b.add(w),()=>{b.delete(w)}};return N={useCrann:l=>{let m=()=>v()[l],w=W=>h({[l]:W}),U=W=>{let pe=m();return M(Re=>{if(l in Re){let me=m(),ke=v();W({current:me,previous:pe,state:ke}),pe=me}},[l])};return[m(),w,U]},get:v,set:h,subscribe:M,getAgentInfo:()=>r,onReady:l=>(o.log("onReady callback added"),g.add(l),E.connected&&(o.log("calling onReady callback"),setTimeout(()=>{l(E)},0)),()=>g.delete(l)),callAction:async(l,...m)=>(o.log("Calling action",l,m),d[l](...m)),onDisconnect:l=>(o.log("onDisconnect callback added"),ue.add(l),()=>{ue.delete(l)}),onReconnect:l=>(o.log("onReconnect callback added"),fe.add(l),()=>{fe.delete(l)})},N}function Ee(){return N!==null}function we(i){let e={};return Object.keys(i).forEach(t=>{let n=i[t];$(n)&&(e[t]=n.default)}),e}var I=require("react");function De(i){return function(t){let{useCrann:n,get:o,set:r,subscribe:a,callAction:g}=(0,I.useMemo)(()=>ae(i),[t]),s=(0,I.useCallback)(u=>{let[p,f]=(0,I.useState)(o()[u]),b=(0,I.useRef)(p);(0,I.useEffect)(()=>{b.current=p},[p]),(0,I.useEffect)(()=>(f(o()[u]),a(M=>{u in M&&f(M[u])},[u])),[u]);let v=(0,I.useCallback)(h=>{r({[u]:h})},[u]);return[p,v]},[o,r,a]),c=(0,I.useCallback)(()=>o(),[o]),d=(0,I.useCallback)(u=>{r(u)},[r]);return{useStateItem:s,getState:c,setState:d,useCrann:n,callAction:g}}}function Le(i){return i}0&&(module.exports={Crann,Partition,Persistence,connect,connected,create,createConfig,createCrannStateHook});
1
+ "use strict";var nt=Object.create;var J=Object.defineProperty;var qe=Object.getOwnPropertyDescriptor;var it=Object.getOwnPropertyNames;var ot=Object.getPrototypeOf,rt=Object.prototype.hasOwnProperty;var st=(r,e)=>()=>(r&&(e=r(r=0)),e);var Ue=(r,e)=>{for(var t in e)J(r,t,{get:e[t],enumerable:!0})},Ke=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of it(e))!rt.call(r,i)&&i!==t&&J(r,i,{get:()=>e[i],enumerable:!(n=qe(e,i))||n.enumerable});return r};var Z=(r,e,t)=>(t=r!=null?nt(ot(r)):{},Ke(e||!r||!r.__esModule?J(t,"default",{value:r,enumerable:!0}):t,r)),Be=r=>Ke(J({},"__esModule",{value:!0}),r),Ae=(r,e,t,n)=>{for(var i=n>1?void 0:n?qe(e,t):e,o=r.length-1,s;o>=0;o--)(s=r[o])&&(i=(n?s(e,t,i):s(i))||i);return n&&i&&J(e,t,i),i};var _e={};Ue(_e,{ActionError:()=>O,ConfigError:()=>te,ConnectionError:()=>xe,CrannError:()=>M,LifecycleError:()=>L,StorageCollisionError:()=>De,ValidationError:()=>H});var M,te,L,xe,O,H,De,G=st(()=>{"use strict";M=class extends Error{constructor(e){super(e),this.name="CrannError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}},te=class extends M{constructor(t,n){super(n?`Config error in '${n}': ${t}`:`Config error: ${t}`);this.field=n;this.name="ConfigError"}},L=class extends M{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"}},xe=class extends M{constructor(t,n,i){super(`Connection error for store "${n}": ${t}`);this.storeName=n;this.reason=i;this.name="ConnectionError"}},O=class extends M{constructor(t,n,i){super(`Action "${t}" failed in store "${n}": ${i}`);this.actionName=t;this.storeName=n;this.reason=i;this.name="ActionError"}},H=class extends M{constructor(t,n,i){super(`Validation failed for action "${t}" in store "${n}": ${i}`);this.actionName=t;this.storeName=n;this.reason=i;this.name="ValidationError"}},De=class extends M{constructor(t){super(`Store name "${t}" is already in use. Each store must have a unique name. If you're trying to connect to an existing store, use connectStore() instead.`);this.storeName=t;this.name="StorageCollisionError"}}});var ft={};Ue(ft,{ActionError:()=>O,Agent:()=>X,ConfigError:()=>te,Crann:()=>ae,CrannError:()=>M,LifecycleError:()=>L,Partition:()=>ne,Persist:()=>P,Persistence:()=>Qe,Scope:()=>N,Store:()=>W,ValidationError:()=>H,clearOrphanedData:()=>Me,connect:()=>Ze,connectStore:()=>Ee,connected:()=>Ye,create:()=>Xe,createConfig:()=>we,createStore:()=>Pe});module.exports=Be(ft);var ze=Z(require("webextension-polyfill"));var Y=(g=>(g.ContentScript="contentscript",g.Extension="extension",g.Popup="popup",g.Sidepanel="sidepanel",g.Devtools="devtools",g.Options="options",g.Unknown="unknown",g))(Y||{});var S=class extends Error{constructor(t,n,i){super(n);this.type=t;this.details=i;this.name="PorterError"}};function Fe(){return typeof ServiceWorkerGlobalScope<"u"&&self instanceof ServiceWorkerGlobalScope}var v=class v{constructor(e){this.context=e}static getLevel(){var t,n,i;return((t=v.globalOptions)==null?void 0:t.level)!==void 0?v.globalOptions.level:typeof process<"u"&&(((n=process.env)==null?void 0:n.NODE_ENV)==="production"||((i=process.env)==null?void 0:i.PORTER_ENV)==="production")?1:4}static configure(e){v.globalOptions=e,e.level!==void 0&&(v.level=e.level),e.enabled!==void 0&&(v.enabled=e.enabled)}static getLogger(e){return this.instances.has(e)||this.instances.set(e,new v(e)),this.instances.get(e)}error(e,...t){v.enabled&&v.level>=0&&console.error(`[Porter:${this.context}] ${e}`,...t)}warn(e,...t){v.enabled&&v.level>=1&&console.warn(`[Porter:${this.context}] ${e}`,...t)}info(e,...t){v.enabled&&v.level>=2&&console.info(`[Porter:${this.context}] ${e}`,...t)}debug(e,...t){v.enabled&&v.level>=3&&console.debug(`[Porter:${this.context}] ${e}`,...t)}trace(e,...t){v.enabled&&v.level>=4&&console.trace(`[Porter:${this.context}] ${e}`,...t)}};v.level=v.getLevel(),v.enabled=!1,v.instances=new Map;var D=v;var Ve=Z(require("webextension-polyfill")),He=require("uuid");var ce=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 p,m;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 i=n.context,o=n.tabId||-1,s=n.frameId||0;this.logger.debug("Determined context for new agent",{determinedContext:i,tabId:o,frameId:s});let g=Array.from(this.agentsInfo.values()).filter(f=>f.location.context===i&&f.location.tabId===o&&f.location.frameId===s);g.length>0&&this.logger.debug("Adding agent: Found existing similar agent.",{tabAgentsInfo:g});let a=((m=(p=this.getAgentByLocation({context:i,tabId:o,frameId:s}))==null?void 0:p.info)==null?void 0:m.id)||(0,He.v4)();this.logger.debug(`Adding agent with id: ${a}`),this.agents.set(a,e);let c={id:a,location:{context:i,tabId:o,frameId:s},createdAt:Date.now(),lastActiveAt:Date.now()};this.agentsInfo.set(a,c),this.logger.debug(`Constructed agent info: ${JSON.stringify(c)}`),e.onMessage.addListener(f=>this.emit("agentMessage",f,c));let d={port:e,info:c};return e.onDisconnect.addListener(()=>{this.emit("agentDisconnect",c),this.logger.debug("Agent disconnected, removing from manager. ",{agentInfo:c}),this.removeAgent(a)}),this.emit("agentSetup",d),this.logger.debug("Setup complete for adding agent. ",{agentInfo:c}),a}getAgentByLocation(e){let{context:t,tabId:n,frameId:i}=e,o=Array.from(this.agentsInfo.entries()).find(([c,d])=>d.location.context===t&&d.location.tabId===n&&d.location.frameId===i);if(o===void 0)return this.logger.error("No agent found for location. ",{location:e}),null;let s=o[0],g=this.agents.get(s),a=this.agentsInfo.get(s);return!g||!a?(this.logger.error("No agent found for location. ",{location:e}),null):{port:g,info:a}}getAgentsByContext(e){return Array.from(this.agentsInfo.entries()).filter(([n,i])=>i.location.context===e).map(([n,i])=>({port:this.agents.get(n),info:i}))}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,i])=>{let o=e.context?i.location.context===e.context:!0,s=e.tabId?i.location.tabId===e.tabId:!0,g=e.frameId?i.location.frameId===e.frameId:!0;return o&&s&&g}).map(([n,i])=>({port:this.agents.get(n),info:i}))}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(i=>i(...t))}identifyConnectionSource(e){var m,f,y,C,u,R,b;let t=e.sender;if(!t)return this.logger.error("Cannot add agent that did not have a sender"),null;let n=Ve.default.runtime.getManifest(),i=((m=n==null?void 0:n.side_panel)==null?void 0:m.default_path)||"",o=n.options_page||"",s=((f=n.action)==null?void 0:f.default_popup)||"",g=n.devtools_page||"",a=((y=n.chrome_url_overrides)==null?void 0:y.newtab)||"",c=((C=n.chrome_url_overrides)==null?void 0:C.bookmarks)||"",d=((u=n.chrome_url_overrides)==null?void 0:u.history)||"",p={sidepanel:i?i.split("/").pop():"sidepanel.html",options:o?o.split("/").pop():"options.html",popup:s?s.split("/").pop():"popup.html",devtools:g?g.split("/").pop():"devtools.html",newtab:a?a.split("/").pop():"newtab.html",bookmarks:c?c.split("/").pop():"bookmarks.html",history:d?d.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 U=new URL(t.url).pathname.split("/").pop();for(let[F,Oe]of Object.entries(p))if(U===Oe)return{context:F,tabId:((R=t.tab)==null?void 0:R.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name};return{context:"unknown",tabId:((b=t.tab)==null?void 0:b.id)||0,frameId:t.frameId||0,url:t.url,portName:e.name}}return{context:"unknown",tabId:0,url:t.url,portName:e.name}}};var le=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 S("invalid-context","Port name not provided");if(!e.name||!e.name.startsWith(this.namespace+":"))throw new S("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 S("invalid-context","Missing context or connection ID. Message was: "+JSON.stringify(t));let i=this.agentOperations.addAgent(e);if(!i)throw new S("invalid-context","Failed to add agent");let o=this.agentOperations.getAgentById(i);o&&this.confirmConnection(o),this.agentOperations.printAgents()}catch(n){this.handleConnectionError(e,n)}}handleConnectionError(e,t){let n=t instanceof S?t:new S("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(i){this.logger.error("Failed to send error message: ",{error:i})}try{e.disconnect()}catch(i){this.logger.error("Failed to disconnect port: ",{error:i})}}confirmConnection(e){if(this.logger.debug("Sending confirmation message back to initiator ",{agent:e}),!e.port)throw new S("invalid-port","Agent port is undefined when confirming connection");e.port.postMessage({action:"porter-handshake",payload:{info:e.info,currentConnections:this.agentOperations.getAllAgentsInfo()}})}};var fe=class{constructor(e,t){this.agentOperations=e;this.logger=t;this.eventListeners=new Map;this.messageListeners=new Set;this.initializationHandler={"porter-messages-established":(n,i)=>{var s;if(!i||!i.id)return;let o=(s=this.agentOperations.getAgentById(i.id))==null?void 0:s.info;if(!o){this.logger.error("No agent info found for agent id: ",i.id);return}this.logger.debug("internalHandlers, established message received: ",i.id,n),this.emitEvent("onMessagesSet",o)}}}async post(e,t){return new Promise((n,i)=>{try{this.logger.debug("Post request received:",{action:e.action,target:t});let o=setTimeout(()=>{let s=new Error("Message posting timed out");this.logger.error("Post timeout:",s),i(s)},5e3);t===void 0?this.broadcastMessage(e):at(t)?this.postToLocation(e,t):gt(t)?this.postToContext(e,t):typeof t=="string"?this.postToId(e,t):this.postToTab(e,t),clearTimeout(o),n()}catch(o){let s=o instanceof Error?o.message:"Unknown error";this.logger.error("Failed to post message:",s),i(new Error(`Failed to post message: ${s}`))}})}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 S("message-failed",`Failed to post message to tabId ${t}`,{originalError:e});return}n.forEach(i=>{i.port&&this.postToPort(e,i.port)})}postToLocation(e,t){this.agentOperations.queryAgents(t).forEach(i=>{if(!i.port)throw new S("invalid-target","No port found for agent",{agentInfo:i.info});this.postToPort(e,i.port)})}postToContext(e,t){this.agentOperations.queryAgents({context:t}).forEach(i=>{if(!i.port)throw new S("invalid-target","No port found for agent",{agentInfo:i.info});this.postToPort(e,i.port)})}postToPort(e,t){try{t.postMessage(e)}catch(n){throw new S("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 S("invalid-target",`No agent found for key: ${t}`);this.postToPort(e,n.port)}onMessage(e){Array.from(this.messageListeners).find(i=>JSON.stringify(i.config)===JSON.stringify(e))&&this.logger.warn(`Listener with same config already exists: ${JSON.stringify(e)}`);let n={config:e,listener:i=>{let o=e[i.message.action];if(o){this.logger.debug("onMessage, calling handler ",{event:i});let{message:s,...g}=i;o(s,g)}else this.logger.debug("onMessage, no handler found ",{event:i})}};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(i=>i(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:i,...o}=e;n(i,o);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:i}of this.messageListeners)i[e.message.action]&&(n(e),t++,this.logger.debug("Message handled by registered listener: ",{listener:n,config:i}));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 at(r){return typeof r=="object"&&r!==null&&"context"in r&&"tabId"in r&&"frameId"in r}function gt(r){return typeof r=="string"&&Object.values(Y).includes(r)}var k=class k{constructor(e,t){if((t==null?void 0:t.debug)!==void 0&&D.configure({enabled:t.debug}),this.logger=D.getLogger("SW"),this.namespace=e||"porter",e||this.logger.error('No namespace provided, defaulting to "porter"'),this.agentManager=new ce(this.logger),this.messageHandler=new fe(this.agentManager,this.logger),this.connectionManager=new le(this.agentManager,this.namespace,this.logger),this.logger.info(`Constructing Porter with namespace: ${this.namespace}`),!Fe())throw new S("invalid-context","Can only create in a service worker");this.agentManager.on("agentMessage",(n,i)=>{this.messageHandler.handleIncomingMessage(n,i)}),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)}),ze.default.runtime.onConnect.addListener(this.connectionManager.handleConnection.bind(this.connectionManager))}static getInstance(e="porter",t){return k.staticLogger.debug(`Getting instance for namespace: ${e}`),k.instances.has(e)?(t==null?void 0:t.debug)!==void 0&&D.configure({enabled:t.debug}):(k.staticLogger.info(`Creating new instance for namespace: ${e}`),k.instances.set(e,new k(e,t))),k.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)}};k.instances=new Map,k.staticLogger=D.getLogger("SW");var Te=k;function V(r="porter",e){let t=Te.getInstance(r,e);return{type:"source",post:t.post.bind(t),onMessage:t.onMessage.bind(t),on:t.on.bind(t),onConnect:t.onConnect.bind(t),onDisconnect:t.onDisconnect.bind(t),onMessagesSet:t.onMessagesSet.bind(t),getAgentById:t.getAgentById.bind(t),getAgentByLocation:t.getAgentByLocation.bind(t),queryAgents:t.queryAgents.bind(t)}}var je=Z(require("webextension-polyfill"));var ue=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 he=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 ue(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=je.default.runtime.connect({name:t});let n=new Promise((i,o)=>{var a;let s=setTimeout(()=>o(new S("connection-timeout","Connection timed out waiting for handshake")),this.CONNECTION_TIMEOUT),g=c=>{var d,p;c.action==="porter-handshake"?(this.logger.debug("Received handshake:",c),clearTimeout(s),this.agentInfo=c.payload.info,this.logger.debug("Handshake agent info:",{agentInfo:this.agentInfo}),(d=this.port)==null||d.onMessage.removeListener(g),i()):c.action==="porter-error"&&(clearTimeout(s),(p=this.port)==null||p.onMessage.removeListener(g),this.logger.error("Error:",c),o(new S(c.payload.type,c.payload.message,c.payload.details)))};(a=this.port)==null||a.onMessage.addListener(g)});(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 i={...t};n&&(i.target=n),this.port.postMessage(i),this.logger.debug("Successfully resent queued message:",{message:i})}catch(i){this.logger.error("Failed to process queued message:",i),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 pe=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,i=this.handlers.get(n)||[];i.length>0?(this.logger.debug(`Found ${i.length} handlers for action: ${n}`),i.forEach(o=>o(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(i){throw new S("message-failed","Failed to post message",{originalError:i,message:t,target:n})}}};var K=class K{constructor(e={}){let t=e.namespace??"porter",n=e.agentContext??this.determineContext();e.debug!==void 0&&D.configure({enabled:e.debug}),this.logger=D.getLogger("Agent"),this.connectionManager=new he(t,this.logger),this.messageHandler=new pe(this.logger),this.connectionManager.onReconnect(i=>{this.logger.info("Reconnected, re-wiring port listeners",{info:i}),this.setupPortListeners()}),this.logger.info("Initializing with options: ",{options:e,context:n}),this.initializeConnection()}static getInstance(e={}){return!K.instance||K.instance.connectionManager.getNamespace()!==e.namespace?K.instance=new K(e):e.debug!==void 0&&D.configure({enabled:e.debug}),K.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(i){this.logger.error("Failed to post message, queueing for retry",{error:i}),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)}};K.instance=null;var Ie=K;function Q(r){let e=Ie.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 ee=require("react");var N={Shared:"shared",Agent:"agent"},P={Local:"local",Session:"session",None:"none"};function $(r){return typeof r=="object"&&r!==null&&"default"in r&&!("handler"in r)}function ct(r){return typeof r=="object"&&r!==null&&"handler"in r}function we(r){let{ConfigError:e}=(G(),Be(_e));if(!r.name)throw new e("'name' is required","name");if(typeof r.name!="string")throw new e("'name' must be a string","name");if(!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(r.name))throw new e("'name' must start with a letter and contain only letters, numbers, underscores, and hyphens","name");if(r.version!==void 0&&(typeof r.version!="number"||!Number.isInteger(r.version)||r.version<1))throw new e("'version' must be a positive integer","version");for(let[t,n]of Object.entries(r))if(!(t==="name"||t==="version"||t==="actions")&&$(n)){if(n.scope!==void 0&&n.scope!==N.Shared&&n.scope!==N.Agent)throw new e(`Invalid scope '${n.scope}'. Must be 'shared' or 'agent'`,t);if(n.persist!==void 0&&n.persist!==P.Local&&n.persist!==P.Session&&n.persist!==P.None)throw new e(`Invalid persist '${n.persist}'. Must be 'local', 'session', or 'none'`,t)}if(r.actions!==void 0){if(typeof r.actions!="object"||r.actions===null)throw new e("'actions' must be an object","actions");for(let[t,n]of Object.entries(r.actions)){if(!ct(n))throw new e(`Action '${t}' must have a 'handler' function`,`actions.${t}`);if(typeof n.handler!="function")throw new e(`Action '${t}' handler must be a function`,`actions.${t}`)}}return{...r,version:r.version??1}}function B(r,e){if(r===e)return!0;if(r==null||typeof r!="object"||e==null||typeof e!="object")return!1;let t=Object.keys(r),n=Object.keys(e);if(t.length!==n.length)return!1;t.sort(),n.sort();for(let i=0;i<t.length;i++){let o=t[i];if(o!==n[i]||!B(r[o],e[o]))return!1}return!0}var me=class{constructor(e,t){this.agentStates=new Map;this.config=e,this.persistence=t,this.defaultSharedState=this.buildDefaultSharedState(),this.defaultAgentState=this.buildDefaultAgentState(),this.sharedState={...this.defaultSharedState}}getState(){return{...this.sharedState}}getSharedState(){return{...this.sharedState}}getAgentState(e){return this.agentStates.get(e)??{...this.defaultAgentState}}getFullStateForAgent(e){let t=this.getAgentState(e);return{...this.sharedState,...t}}setState(e,t){let n={},i={};for(let o of Object.keys(e)){let s=this.config[o];if(!$(s))continue;let g=e[o],a=s.scope===N.Agent;a&&t?i[o]=g:a||(n[o]=g)}if(Object.keys(n).length>0){let o={...this.sharedState,...n};B(this.sharedState,o)||(this.sharedState=o)}if(t&&Object.keys(i).length>0){let o=this.agentStates.get(t)??{...this.defaultAgentState},s={...o,...i};B(o,s)||this.agentStates.set(t,s)}return{sharedChanges:n,agentChanges:i}}setAgentState(e,t){let n=this.agentStates.get(e)??{...this.defaultAgentState},i={...n,...t};B(n,i)||this.agentStates.set(e,i)}hydrateSharedState(e){this.sharedState={...this.defaultSharedState,...e}}initializeAgentState(e){this.agentStates.has(e)||this.agentStates.set(e,{...this.defaultAgentState})}removeAgentState(e){this.agentStates.delete(e)}clear(){this.sharedState={...this.defaultSharedState},this.agentStates.clear()}buildDefaultSharedState(){let e={};for(let[t,n]of Object.entries(this.config))t==="name"||t==="version"||t==="actions"||$(n)&&(!n.scope||n.scope===N.Shared)&&(e[t]=n.default);return e}buildDefaultAgentState(){let e={};for(let[t,n]of Object.entries(this.config))t==="name"||t==="version"||t==="actions"||$(n)&&n.scope===N.Agent&&(e[t]=n.default);return e}};var I=Z(require("webextension-polyfill"));var ye=class{constructor(e,t={}){this.config=e,this.options=t}buildKey(e){return`crann:${this.config.name}:v${this.config.version}:${e}`}parseKey(e){let t=e.match(/^crann:([^:]+):v(\d+):(.+)$/);return t?{name:t[1],version:parseInt(t[2],10),key:t[3]}:null}getMetaKey(){return`crann:${this.config.name}:__meta`}async hydrate(){let[e,t]=await Promise.all([I.default.storage.local.get(null),I.default.storage.session.get(null)]),n={...e,...t},i={};for(let[o,s]of Object.entries(this.config)){if(o==="name"||o==="version"||o==="actions"||!$(s)||s.scope==="agent"||!s.persist||s.persist===P.None)continue;let g=this.buildKey(o);g in n&&(i[o]=n[g])}return await this.updateMetadata(),i}async persist(e){let t={},n={};for(let[o,s]of Object.entries(e)){let g=this.config[o];if(!$(g))continue;let a=this.buildKey(o);switch(g.persist){case P.Local:t[a]=s;break;case P.Session:n[a]=s;break}}let i=[];Object.keys(t).length>0&&i.push(I.default.storage.local.set(t)),Object.keys(n).length>0&&i.push(I.default.storage.session.set(n)),await Promise.all(i)}async clearAll(){let e=[];for(let[t,n]of Object.entries(this.config))t==="name"||t==="version"||t==="actions"||$(n)&&n.persist&&n.persist!==P.None&&e.push(this.buildKey(t));e.push(this.getMetaKey()),await Promise.all([I.default.storage.local.remove(e),I.default.storage.session.remove(e)])}async updateMetadata(){var i;let e=this.getMetaKey(),t=await I.default.storage.local.get(e),n={version:this.config.version,createdAt:((i=t[e])==null?void 0:i.createdAt)??Date.now(),lastAccessed:Date.now()};await I.default.storage.local.set({[e]:n})}};async function Me(r){let{keepStores:e,dryRun:t=!1}=r,[n,i]=await Promise.all([I.default.storage.local.get(null),I.default.storage.session.get(null)]),o=new Set([...Object.keys(n),...Object.keys(i)]),s=[];for(let g of o){if(!g.startsWith("crann:"))continue;let a=g.match(/^crann:([^:]+):/);if(!a)continue;let c=a[1];e.includes(c)||s.push(g)}return!t&&s.length>0&&await Promise.all([I.default.storage.local.remove(s),I.default.storage.session.remove(s)]),{keys:s,count:s.length}}var Se=class{constructor(){this.agents=new Map}add(e){let t={id:e.id,tabId:e.location.tabId,frameId:e.location.frameId,context:e.location.context,connectedAt:Date.now()};return this.agents.set(e.id,t),t}remove(e){return this.agents.delete(e)}get(e){return this.agents.get(e)}getAll(){return Array.from(this.agents.values())}query(e){return this.getAll().filter(t=>!(e.context!==void 0&&t.context!==e.context||e.tabId!==void 0&&t.tabId!==e.tabId||e.frameId!==void 0&&t.frameId!==e.frameId))}has(e){return this.agents.has(e)}get size(){return this.agents.size}clear(){this.agents.clear()}};G();var ve=class{constructor(e,t,n){this.config=e,this.getState=t,this.setState=n}async execute(e,t,n){let i=this.config.actions;if(!i)throw new O(e,this.config.name,"No actions defined");let o=i[e];if(!o)throw new O(e,this.config.name,"Unknown action");if(o.validate)try{o.validate(...t)}catch(g){throw new H(e,this.config.name,g instanceof Error?g.message:String(g))}let s={state:this.getState(),setState:async g=>{await this.setState(g,n.id)},agentId:n.id,agentLocation:n.location};try{return await o.handler(s,...t)}catch(g){throw new O(e,this.config.name,g instanceof Error?g.message:String(g))}}hasAction(e){var t;return((t=this.config.actions)==null?void 0:t[e])!==void 0}getActionNames(){return Object.keys(this.config.actions??{})}};G();var W=class{constructor(e,t={}){this.stateChangeListeners=new Set;this.agentConnectListeners=new Set;this.agentDisconnectListeners=new Set;this.isDestroyed=!1;this.config=e,this.options=t,this.porter=V(e.name,{debug:t.debug??!1}),this.persistence=new ye(e,t),this.stateManager=new me(e,this.persistence),this.agentRegistry=new Se,this.actionExecutor=new ve(e,()=>this.getState(),(n,i)=>this.setState(n,i)),this.setupMessageHandlers(),this.hydrate()}getState(){return this.assertNotDestroyed(),this.stateManager.getState()}getAgentState(e){return this.assertNotDestroyed(),this.stateManager.getAgentState(e)}async setState(e,t){this.assertNotDestroyed();let{sharedChanges:n,agentChanges:i}=this.stateManager.setState(e,t);Object.keys(n).length>0&&await this.persistence.persist(n),this.notifyStateChange(e,t)}async setAgentState(e,t){this.assertNotDestroyed(),this.stateManager.setAgentState(e,t),this.notifyStateChange(t,e)}async clear(){this.assertNotDestroyed(),this.stateManager.clear(),await this.persistence.clearAll(),this.notifyStateChange({})}subscribe(e){return this.assertNotDestroyed(),this.stateChangeListeners.add(e),()=>{this.stateChangeListeners.delete(e)}}onAgentConnect(e){return this.assertNotDestroyed(),this.agentConnectListeners.add(e),()=>{this.agentConnectListeners.delete(e)}}onAgentDisconnect(e){return this.assertNotDestroyed(),this.agentDisconnectListeners.add(e),()=>{this.agentDisconnectListeners.delete(e)}}getAgents(e){return this.assertNotDestroyed(),e?this.porter.queryAgents(e).map(n=>this.agentRegistry.get(n.info.id)).filter(n=>n!==void 0):this.agentRegistry.getAll()}destroy(e){this.isDestroyed||(this.isDestroyed=!0,this.stateChangeListeners.clear(),this.agentConnectListeners.clear(),this.agentDisconnectListeners.clear(),this.agentRegistry.clear(),e!=null&&e.clearPersisted&&this.persistence.clearAll())}setupMessageHandlers(){let e=new Set;this.porter.on({setState:(t,n)=>{n&&this.setState(t.payload.state,n.id)}}),this.porter.onMessagesSet(t=>{if(!t||e.has(t.id))return;e.add(t.id);let n=this.stateManager.getFullStateForAgent(t.id);this.porter.post({action:"initialState",payload:{state:n,info:t}},t.location)}),this.porter.onConnect(t=>{if(!t)return;let n=this.agentRegistry.add(t);this.stateManager.initializeAgentState(t.id),this.agentConnectListeners.forEach(i=>i(n))}),this.porter.onDisconnect(t=>{if(!t)return;let n=this.agentRegistry.get(t.id);n&&(this.agentRegistry.remove(t.id),this.stateManager.removeAgentState(t.id),e.delete(t.id),this.agentDisconnectListeners.forEach(i=>i(n)))}),this.setupRpcHandlers()}setupRpcHandlers(){this.porter.on({rpc:async(e,t)=>{if(!t)return;let{actionName:n,args:i}=e.payload;try{let o=await this.actionExecutor.execute(n,i,t);this.porter.post({action:"rpcResult",payload:{actionName:n,result:o,success:!0}},t.location)}catch(o){this.porter.post({action:"rpcResult",payload:{actionName:n,error:o instanceof Error?o.message:String(o),success:!1}},t.location)}}})}async hydrate(){let e=await this.persistence.hydrate();Object.keys(e).length>0&&this.stateManager.hydrateSharedState(e)}notifyStateChange(e,t){var o;let n=this.getState(),i=t?(o=this.porter.getAgentById(t))==null?void 0:o.info:void 0;if(this.stateChangeListeners.forEach(s=>{s(n,e,i)}),t){let s=this.porter.getAgentById(t);s!=null&&s.info.location&&this.porter.post({action:"stateUpdate",payload:{state:e}},s.info.location)}else for(let s of this.agentRegistry.getAll())this.porter.post({action:"stateUpdate",payload:{state:e}},s.id)}assertNotDestroyed(){if(this.isDestroyed)throw new L(this.config.name,"store")}};function Pe(r,e){return new W(r,e)}G();var X=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,i;typeof e=="function"?i=e:(n=e,i=t);let o={keys:n,callback:i};return this.subscribers.add(o),()=>{this.subscribers.delete(o)}}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(i=>{try{i(this._state)}catch(o){console.error("[Crann Agent] Error in onReady callback:",o)}}),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(i=>i 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:i,result:o,error:s,success:g}=n.payload,a=e.get(i);a&&(e.delete(i),g?a.resolve(o):a.reject(new Error(s)))}}),new Proxy({},{get:(n,i)=>async(...o)=>{let s=`${t++}`;return new Promise((g,a)=>{e.set(s,{resolve:g,reject:a}),this.porter.post({action:"rpc",payload:{callId:s,actionName:i,args:o}})})}})}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 L(this.config.name,"agent")}};function Ee(r,e){return new X(r,e)}G();var se=Z(require("webextension-polyfill"));var ne={Instance:"instance",Service:"service"},Qe={Session:"session",Local:"local",None:"none"},ie=r=>!("handler"in r),Ce=r=>"handler"in r;var oe=class oe{static setDebug(e){oe._debug=e}static isDebugEnabled(){return oe._debug}};oe._debug=!1;var re=oe;function Ge(){return re.isDebugEnabled()}function Re(r,e,t){let n=t.value;return t.value=function(...i){var o;if(Ge()){let s=new Error().stack,a=(o=((s==null?void 0:s.split(`
2
+ `))||[])[3])==null?void 0:o.match(/at\s+(\S+)\s+/),c=a?a[1]:"unknown",d=i.length>1?i[1]:void 0,p={source:c,timestamp:Date.now(),instanceKey:i[0],changes:d};console.log("Crann State Change:",p)}return n.apply(this,i)},t}var A=class A{constructor(e){this.tag=null;this.context=e}static setDebug(e){A.debug=e}static setPrefix(e){A.prefix=e}setTag(e){this.tag=e}withTag(e){let t=new A(this.context);return t.setTag(e),t}getFullContext(){return this.tag?`${this.context}:${this.tag}`:this.context}createLogMethods(){let e=this.getFullContext(),t=`%c${A.prefix}%c [%c${e}%c]`,n="color: #3fcbff; font-weight: bold",i="color: #d58cff; font-weight: bold",o="";return A.debug?{debug:console.log.bind(console,t,n,o,i,o),log:console.log.bind(console,t,n,o,i,o),info:console.info.bind(console,t,n,o,i,o),warn:console.warn.bind(console,t,n,o,i,o),error:console.error.bind(console,t,n,o,i,o)}:{debug:A.noOp,log:A.noOp,info:A.noOp,warn:A.noOp,error:A.noOp}}get debug(){return this.createLogMethods().debug}get log(){return this.createLogMethods().log}get info(){return this.createLogMethods().info}get warn(){return this.createLogMethods().warn}get error(){return this.createLogMethods().error}static forContext(e,t){let n=new A(e);return t&&n.setTag(t),n}};A.debug=!1,A.prefix="CrannLogger",A.noOp=function(){};var x=A;function T(r,e={terse:!0}){let n=(i=>{let o=String(i);return o.length>=4?o.slice(-4):o.padStart(4,"0")})(r.location.tabId);return e!=null&&e.terse?`${n}:${r.location.frameId}`:`${r.location.context}:${n}:${r.location.frameId}`}function We(r,e,t,n,i){var d,p;let o=new Map,s=new Map,g=(d=r.context)!=null&&d.isServiceWorker?"Core":"Agent",a=x.forContext(`${g}:RPC`);return(p=r.context)!=null&&p.agentInfo&&a.setTag(T(r.context.agentInfo)),r.addEventListener("message",m=>{a.debug("Message received:",m);let[f,y]=m.data;if("call"in y&&"args"in y.call){a.debug("Processing call message:",y);let C=y.call,{id:u,args:R,target:b}=C,j=t[u];if(!j){r.postMessage([f,{error:{id:u,error:"Action not found",target:b}}]);return}try{if(j.validate&&j.validate(...R),!b){r.postMessage([f,{error:{id:u,error:"No target provided for action call",target:b}}]);return}let U=e();a.debug("Executing action with most current state:",U),Promise.resolve(j.handler(U,n,b,...R)).then(F=>{a.debug("Action handler result:",{result:F,target:b}),r.postMessage([f,{result:{id:u,result:F,target:b}}])},F=>{r.postMessage([f,{error:{id:u,error:F.message,target:b}}])})}catch(U){U instanceof Error?r.postMessage([f,{error:{id:u,error:U.message,target:b}}]):r.postMessage([f,{error:{id:u,error:"Unknown error occurred",target:b}}])}}else if("result"in y){let C=y.result,u=o.get(f);u&&(u(C.result),o.delete(f))}else if("error"in y){let C=y.error,u=o.get(f);u&&(u(Promise.reject(new Error(C.error))),o.delete(f))}else if("release"in y){let C=y.release,u=s.get(C.id);u&&(u.clear(),s.delete(C.id))}}),new Proxy({},{get(m,f){return(...y)=>{let C=Math.random();return new Promise((u,R)=>{o.set(C,b=>{b instanceof Promise?b.then(u,R):u(b)}),r.postMessage([C,{call:{id:f,args:y}}])})}}})}function be(r,e,t,n){let i=t||V("crann"),o=i.type!=="agent",s=x.forContext(o?"Core:RPC":"Agent:RPC"),g={postMessage:(a,c)=>{if(o){s.debug("Posting message from service worker:",{message:a,transferables:c});let[,d]=a,p=lt(d);if(!p){s.warn("No target specified for RPC response in service worker");return}i.post({action:"rpc",payload:{message:a,transferables:c||[]}},p)}else{let d=i.getAgentInfo();if(!d){s.warn("No agent info found for posting message",{agentInfo:d});return}let p=T(d),[,m]=a;"call"in m&&(m.call.target=d==null?void 0:d.location),s.withTag(p).debug("Sending RPC message from agent:",{rpcPayload:m,message:a}),i.post({action:"rpc",payload:{message:a,transferables:c||[]}})}},addEventListener:(a,c)=>{i.on({rpc:(d,p)=>{try{if(!p)s.debug("RPC message received:",{message:d,event:a});else{let u=T(p);s.withTag(u).debug("RPC message received:",{message:d,event:a})}let{payload:m}=d,{message:f,transferables:y=[]}=m,C=new MessageEvent("message",{data:f,ports:y.filter(u=>u instanceof MessagePort)||[]});c(C)}catch(m){s.error("Failed to parse RPC message payload:",m)}}})},removeEventListener:()=>{},context:{isServiceWorker:o,agentInfo:o?void 0:i.getAgentInfo()}};return We(g,r,e,n)}function lt(r){if("result"in r)return r.result.target;if("error"in r)return r.error.target;if("call"in r)return r.call.target;if("release"in r)return r.release.target}var q=class q{constructor(e,t){this.config=e;this.instances=new Map;this.stateChangeListeners=[];this.instanceReadyListeners=[];this.storagePrefix="crann_";this.porter=V("crann",{debug:!1});t!=null&&t.debug&&(re.setDebug(!0),x.setDebug(!0)),this.storagePrefix=(t==null?void 0:t.storagePrefix)??this.storagePrefix,this.logger=x.forContext("Core"),this.logger.log("Constructing Crann with new logger"),this.defaultInstanceState=this.initializeInstanceDefault(),this.defaultServiceState=this.serviceState=this.initializeServiceDefault(),this.hydrate(),this.logger.log("Crann constructed, setting initial message handlers"),this.porter.on({setState:(a,c)=>{if(!c){this.logger.warn("setState message heard from unknown agent");return}let d=T(c);this.logger.withTag(d).log("Setting state:",a),this.set(a.payload.state,c.id)}});let n=new Set;this.porter.onMessagesSet(a=>{if(!a){this.logger.error("Messages set but no agent info.",{info:a});return}let c=T(a);if(this.logger.withTag(c).log("onMessagesSet received for agent:",{id:a.id,context:a.location.context,tabId:a.location.tabId,frameId:a.location.frameId,alreadyInitialized:n.has(a.id)}),n.has(a.id)){this.logger.withTag(c).log("Already sent initialState to agent, skipping:",a.id);return}n.add(a.id),this.logger.withTag(c).log("Messages set received. Sending initial state.",{info:a});let d=this.get(a.id);this.porter.post({action:"initialState",payload:{state:d,info:a}},a.location),this.notifyInstanceReady(a.id,a)}),this.porter.onConnect(a=>{if(!a){this.logger.error("Agent connected but no agent info.",{info:a});return}let c=T(a);this.logger.withTag(c).log("Agent connected",{info:a}),this.addInstance(a.id,c),this.porter.onDisconnect(d=>{this.logger.withTag(T(d)).log("Agent disconnect heard. Connection type, context and location:",{info:d}),this.removeInstance(d.id)})});let o=(a,c)=>c!==void 0?this.set(a,c):this.set(a),s=this.extractActions(e),g=()=>{let a=this.get();return this.logger.log("State getter called, returning current state:",a),a};this.rpcEndpoint=be(g,s,this.porter,o)}static getInstance(e,t){return q.instance?t!=null&&t.debug&&x.forContext("Core").log("Instance requested and already existed, returning"):q.instance=new q(e,t),q.instance}async addInstance(e,t){if(this.instances.has(e))this.logger.withTag(t).log("Instance was already registered, ignoring request from key");else{this.logger.withTag(t).log("Adding instance from agent key");let n={...this.defaultInstanceState};this.instances.set(e,n)}}async removeInstance(e){this.instances.has(e)?(this.logger.withTag(e).log("Remove instance requested"),this.instances.delete(e)):this.logger.withTag(e).log("Remove instance requested but it did not exist!")}async setServiceState(e){this.logger.log("Request to set service state with update:",e),this.logger.log("Existing service state was ",this.serviceState);let t={...this.serviceState,...e};B(this.serviceState,t)?this.logger.log("New state seems to be the same as existing, skipping"):(this.logger.log("Confirmed new state was different than existing so proceeding to persist then notify all connected instances."),this.serviceState=t,await this.persist(e),this.notify(e))}async setInstanceState(e,t){this.logger.withTag(e).log("Request to update instance state, update:",t);let n=this.instances.get(e)||this.defaultInstanceState,i={...n,...t};B(n,i)?this.logger.withTag(e).log("Instance state update is not different, skipping update."):(this.logger.withTag(e).log("Instance state update is different, updating and notifying."),this.instances.set(e,i),this.notify(t,e))}async persist(e){this.logger.log("Persisting state");let t=!1;for(let n in e||this.serviceState){let o=this.config[n].persist||"none",s=e?e[n]:this.serviceState[n];switch(o){case"session":await se.default.storage.session.set({[this.storagePrefix+n]:s}),t=!0;break;case"local":await se.default.storage.local.set({[this.storagePrefix+n]:s}),t=!0;break;default:break}}t?this.logger.log("State was persisted"):this.logger.log("Nothing to persist")}async clear(){this.logger.log("Clearing state"),this.serviceState=this.defaultServiceState,this.instances.forEach((e,t)=>{this.instances.set(t,this.defaultInstanceState)}),await this.persist(),this.notify({})}subscribe(e){this.logger.log("Subscribing to state"),this.stateChangeListeners.push(e)}notify(e,t){let n=t?this.porter.getAgentById(t):void 0,i=t?this.get(t):this.get();this.stateChangeListeners.length>0&&(this.logger.log("Notifying state change listeners in source"),this.stateChangeListeners.forEach(o=>{o(i,e,n==null?void 0:n.info)})),t&&(n!=null&&n.info.location)?(this.logger.withTag(t).log("Notifying of state change."),this.porter.post({action:"stateUpdate",payload:{state:e}},n.info.location)):(this.logger.log("Notifying everyone"),this.instances.forEach((o,s)=>{this.porter.post({action:"stateUpdate",payload:{state:e}},s)}))}get(e){return e?{...this.serviceState,...this.instances.get(e)}:{...this.serviceState}}findInstance(e){let t=this.porter.getAgentByLocation(e);if(!t)return this.logger.log("Could not find agent for location:",{location:e}),null;for(let[n,i]of this.instances)if(n===t.info.id)return this.logger.log("Found instance for key:",n),n;return this.logger.log("Could not find instance for context and location:",{location:e}),null}queryAgents(e){return this.porter.queryAgents(e)}async set(e,t){let n={},i={};for(let o in e){let s=this.config[o];if(dt(s)){if(s.partition==="instance"){let g=o,a=e;n[g]=a[g]}else if(!s.partition||s.partition===ne.Service){let g=o,a=e;i[g]=a[g]}}}t&&Object.keys(n).length>0&&(this.logger.withTag(t).log("Setting instance state:",n),this.setInstanceState(t,n)),Object.keys(i).length>0&&(this.logger.log("Setting service state:",i),this.setServiceState(i))}async hydrate(){this.logger.log("Hydrating state from storage.");let e=await se.default.storage.local.get(null),t=await se.default.storage.session.get(null),n={...e,...t};this.logger.log("Storage data is:",{local:e,session:t,combined:n});let i={},o=!1;for(let s in n){let g=this.removePrefix(s);if(this.logger.log(`Checking storage key ${s} -> ${g}`),this.config.hasOwnProperty(g)){let a=n[s];this.logger.log(`Found storage value for ${g}:`,a),i[g]=a,o=!0}}o?this.logger.log("Hydrated some items."):this.logger.log("No items found in storage."),this.serviceState={...this.defaultServiceState,...i}}removePrefix(e){return e.startsWith(this.storagePrefix)?e.replace(this.storagePrefix,""):e}initializeInstanceDefault(){let e={};return Object.keys(this.config).forEach(t=>{let n=this.config[t];ie(n)&&n.partition==="instance"&&(e[t]=n.default)}),e}initializeServiceDefault(){this.logger.log("Initializing service default state"),this.logger.log("Config is:",this.config);let e={};return Object.keys(this.config).forEach(t=>{let n=this.config[t];this.logger.log("Item is:",n),ie(n)&&(!n.partition||n.partition===ne.Service)&&(e[t]=n.default,this.logger.log("Setting service state for key:",t,"to",n.default))}),this.logger.log("Final service state is:",e),e}subscribeToInstanceReady(e){return this.logger.log("Subscribing to instance ready events"),this.instanceReadyListeners.push(e),this.instances.forEach((t,n)=>{let i=this.porter.getAgentById(n);i!=null&&i.info&&e(n,i.info)}),()=>{this.logger.log("Unsubscribing from instance ready events");let t=this.instanceReadyListeners.indexOf(e);t!==-1&&this.instanceReadyListeners.splice(t,1)}}notifyInstanceReady(e,t){if(this.instanceReadyListeners.length>0){let n=T(t);this.logger.withTag(n).log("Notifying instance ready listeners"),this.instanceReadyListeners.forEach(i=>{i(e,t)})}}extractActions(e){return Object.entries(e).filter(([t,n])=>Ce(n)).reduce((t,[n,i])=>{let o=i;return{...t,[n]:o}},{})}};q.instance=null,Ae([Re],q.prototype,"setServiceState",1),Ae([Re],q.prototype,"setInstanceState",1);var ae=q;function Xe(r,e){let t=ae.getInstance(r,e);return{get:t.get.bind(t),set:t.set.bind(t),subscribe:t.subscribe.bind(t),onInstanceReady:t.subscribeToInstanceReady.bind(t),findInstance:t.findInstance.bind(t),queryAgents:t.queryAgents.bind(t),clear:t.clear.bind(t)}}function dt(r){return r&&typeof r=="object"&&"default"in r}var E={connected:!1},z=null,ke=new Set,Le=new Set;function Ze(r,e){let t=(e==null?void 0:e.debug)||!1,n=e==null?void 0:e.context;t&&x.setDebug(!0);let i=x.forContext("Agent"),o,s="unset",g=new Set;if(i.log("Initializing Crann Agent"+(n?` with context: ${n}`:"")),z&&E.connected)return i.log("We had an instance already and it's connected, returning"),i.log("Connect, calling onReady callback"),setTimeout(()=>{g.forEach(l=>l(E))},0),z;z&&!E.connected&&(i.log("We had an instance but it's disconnected, creating new connection"),z=null),i.log("No existing instance, creating a new one");let a=Q({namespace:"crann",debug:!1});i.log("Porter connection created"),a.onDisconnect(()=>{i.log("Porter connection lost, updating connection status"),E={connected:!1},ke.forEach(l=>{try{l()}catch(h){i.error("Error in disconnect callback:",h)}}),g.forEach(l=>{try{l(E)}catch(h){i.error("Error in onReady callback during disconnect:",h)}})}),a.onReconnect(l=>{i.log("Porter reconnected, updating connection status",l),E={connected:!0,agent:l},o=l,s=T(l),i.setTag(s),Le.forEach(h=>{try{h(l)}catch(w){i.error("Error in reconnect callback:",w)}}),g.forEach(h=>{try{h(E)}catch(w){i.error("Error in onReady callback during reconnect:",w)}})});let c=Object.entries(r).filter(([l,h])=>Ce(h)).reduce((l,[h,w])=>{let _=w;return{...l,[h]:{type:"action",handler:_.handler,validate:_.validate}}},{}),d=be(()=>Je(r),c,a),p=!1;a.on({initialState:l=>{if(i.log("initialState received",{alreadyReceived:p,payload:l.payload}),p){i.log("Ignoring duplicate initialState message");return}p=!0,m=l.payload.state,o=l.payload.info,s=T(o),E={connected:!0,agent:o},i.setTag(s),i.log(`Initial state received and ${y.size} listeners notified`,{message:l}),g.forEach(h=>{i.log("Calling onReady callbacks"),h(E)}),y.forEach(h=>{h.callback(m)})},stateUpdate:l=>{f=l.payload.state,m={...m,...f},i.log("State updated:",{message:l,changes:f,_state:m}),f&&y.forEach(h=>{(h.keys===void 0||h.keys.some(_=>_ in f))&&h.callback(f)})}}),i.log("Porter connected. Setting up state and listeners");let m=Je(r),f=null,y=new Set;i.log("Completed setup, returning instance");let C=()=>m,u=l=>{i.log("Calling post with setState",l),a.post({action:"setState",payload:{state:l}})},R=(l,h)=>{let w={keys:h,callback:l};return y.add(w),()=>{y.delete(w)}};return z={useCrann:l=>{let h=()=>C()[l],w=ge=>u({[l]:ge}),_=ge=>{let Ne=h();return R(et=>{if(l in et){let $e=h(),tt=C();ge({current:$e,previous:Ne,state:tt}),Ne=$e}},[l])};return[h(),w,_]},get:C,set:u,subscribe:R,getAgentInfo:()=>o,onReady:l=>(i.log("onReady callback added"),g.add(l),E.connected&&(i.log("calling onReady callback"),setTimeout(()=>{l(E)},0)),()=>g.delete(l)),callAction:async(l,...h)=>(i.log("Calling action",l,h),d[l](...h)),onDisconnect:l=>(i.log("onDisconnect callback added"),ke.add(l),()=>{ke.delete(l)}),onReconnect:l=>(i.log("onReconnect callback added"),Le.add(l),()=>{Le.delete(l)})},z}function Ye(){return z!==null}function Je(r){let e={};return Object.keys(r).forEach(t=>{let n=r[t];ie(n)&&(e[t]=n.default)}),e}0&&(module.exports={ActionError,Agent,ConfigError,Crann,CrannError,LifecycleError,Partition,Persist,Persistence,Scope,Store,ValidationError,clearOrphanedData,connect,connectStore,connected,create,createConfig,createStore});
3
3
  //# sourceMappingURL=index.js.map