crann 1.0.39 → 1.0.40

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts", "../../src/crann.ts", "../../src/model/crann.model.ts", "../../src/utils/deepEqual.ts", "../../src/utils/debug.ts", "../../src/utils/tracking.ts", "../../src/rpc/adapter.ts", "../../src/utils/logger.ts", "../../src/utils/agent.ts", "../../src/rpc/endpoint.ts", "../../src/crannAgent.ts", "../../src/hooks/useCrannState.ts"],
4
- "sourcesContent": ["export { create, Crann } from \"./crann\";\nexport { connect, connected } from \"./crannAgent\";\nexport { createCrannStateHook } from \"./hooks/useCrannState\";\nexport {\n CrannAgent,\n StateUpdate,\n State,\n Partition,\n Persistence,\n ConfigItem,\n DerivedState,\n} from \"./model/crann.model\";\n", "import browser from \"webextension-polyfill\";\nimport {\n DerivedInstanceState,\n DerivedServiceState,\n ConfigItem,\n DerivedState,\n Partition,\n CrannOptions,\n ActionDefinition,\n AnyConfig,\n isStateItem,\n isActionItem,\n} from \"./model/crann.model\";\nimport { AgentInfo, source, Agent } from \"porter-source\";\nimport { deepEqual } from \"./utils/deepEqual\";\nimport { BrowserLocation } from \"porter-source\";\nimport { trackStateChange } from \"./utils/tracking\";\nimport { DebugManager } from \"./utils/debug\";\nimport { createCrannRPCAdapter } from \"./rpc/adapter\";\nimport { Logger } from \"./utils/logger\";\nimport { getAgentTag } from \"./utils/agent\";\n\nexport class Crann<TConfig extends AnyConfig> {\n private static instance: Crann<any> | null = null;\n private instances: Map<string, DerivedInstanceState<TConfig>> = new Map();\n private defaultServiceState: DerivedServiceState<TConfig>;\n private defaultInstanceState: DerivedInstanceState<TConfig>;\n private serviceState: DerivedServiceState<TConfig>;\n private stateChangeListeners: Array<\n (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedServiceState<TConfig> & DerivedInstanceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n > = [];\n private instanceReadyListeners: Array<\n (instanceId: string, agent: AgentInfo) => void\n > = [];\n private storagePrefix = \"crann_\";\n private porter = source(\"crann\", { debug: false });\n private rpcEndpoint: ReturnType<typeof createCrannRPCAdapter>;\n private logger: Logger;\n\n constructor(private config: TConfig, options?: CrannOptions) {\n // Set the debug flag globally\n if (options?.debug) {\n DebugManager.setDebug(true);\n Logger.setDebug(true);\n }\n this.storagePrefix = options?.storagePrefix ?? this.storagePrefix;\n\n // Set up the core logger\n this.logger = Logger.forContext(\"Core\");\n this.logger.log(\"Constructing Crann with new logger\");\n\n // Hydrate the initial state from the config defaults and from storage\n this.defaultInstanceState = this.initializeInstanceDefault();\n this.defaultServiceState = this.serviceState =\n this.initializeServiceDefault();\n this.hydrate();\n\n // Set up the message handlers\n this.logger.log(\"Crann constructed, setting initial message handlers\");\n this.porter.on({\n setState: (message, info) => {\n if (!info) {\n this.logger.warn(\"setState message heard from unknown agent\");\n return;\n }\n\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Setting state:\", message);\n this.set(message.payload.state, info.id);\n },\n });\n\n // Track which agents we've already sent initialState to\n const agentsInitialized = new Set<string>();\n\n // Once the agents are connected and have set up their listeners, send them the initial state\n this.porter.onMessagesSet((info: AgentInfo) => {\n if (!info) {\n this.logger.error(\"Messages set but no agent info.\", { info });\n return;\n }\n\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"onMessagesSet received for agent:\", {\n id: info.id,\n context: info.location.context,\n tabId: info.location.tabId,\n frameId: info.location.frameId,\n alreadyInitialized: agentsInitialized.has(info.id),\n });\n\n // Skip sending initialState if we've already sent it to this agent\n if (agentsInitialized.has(info.id)) {\n this.logger\n .withTag(agentTag)\n .log(\"Already sent initialState to agent, skipping:\", info.id);\n return;\n }\n\n // Add the agent to the set of agents we've already sent initialState to\n agentsInitialized.add(info.id);\n\n this.logger\n .withTag(agentTag)\n .log(\"Messages set received. Sending initial state.\", { info });\n const fullState = this.get(info.id);\n this.porter.post(\n {\n action: \"initialState\",\n payload: { state: fullState, info },\n },\n info.location\n );\n\n this.notifyInstanceReady(info.id, info);\n });\n\n // Handle agent connection and disconnection\n this.porter.onConnect((info: AgentInfo) => {\n if (!info) {\n this.logger.error(\"Agent connected but no agent info.\", { info });\n return;\n }\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Agent connected\", { info });\n this.addInstance(info.id, agentTag);\n this.porter.onDisconnect((info: AgentInfo) => {\n this.logger\n .withTag(getAgentTag(info))\n .log(\n \"Agent disconnect heard. Connection type, context and location:\",\n { info }\n );\n this.removeInstance(info.id);\n });\n });\n\n // Initialize RPC with actions\n const actions = this.extractActions(config);\n this.rpcEndpoint = createCrannRPCAdapter(\n this.get(),\n actions,\n this.porter,\n (newState: Partial<DerivedState<TConfig>>) => this.set(newState)\n );\n }\n\n public static getInstance<TConfig extends AnyConfig>(\n config: TConfig,\n options?: CrannOptions\n ): Crann<TConfig> {\n if (!Crann.instance) {\n Crann.instance = new Crann(config, options);\n } else if (options?.debug) {\n const logger = Logger.forContext(\"Core\");\n logger.log(\"Instance requested and already existed, returning\");\n }\n return Crann.instance;\n }\n\n /**\n * Add an instance to the Crann instance.\n * @param key The key of the instance to add.\n * @param agentTag The tag of the agent that is adding the instance, for logging.\n */\n private async addInstance(key: string, agentTag: string): Promise<void> {\n if (!this.instances.has(key)) {\n this.logger.withTag(agentTag).log(\"Adding instance from agent key\");\n const initialInstanceState = {\n ...this.defaultInstanceState,\n } as DerivedInstanceState<TConfig>;\n this.instances.set(key, initialInstanceState);\n } else {\n this.logger\n .withTag(agentTag)\n .log(\"Instance was already registered, ignoring request from key\");\n }\n }\n\n private async removeInstance(key: string): Promise<void> {\n if (this.instances.has(key)) {\n this.logger.withTag(key).log(\"Remove instance requested\");\n this.instances.delete(key);\n } else {\n this.logger\n .withTag(key)\n .log(\"Remove instance requested but it did not exist!\");\n }\n }\n\n @trackStateChange\n public async setServiceState(\n state: Partial<DerivedServiceState<TConfig>>\n ): Promise<void> {\n this.logger.log(\"Request to set service state with:\", state);\n const update = { ...this.serviceState, ...state };\n if (!deepEqual(this.serviceState, update)) {\n this.logger.log(\n \"Confirmed new state was different than existing so proceeding to persist then notify all connected instances.\"\n );\n this.serviceState = update;\n await this.persist(state);\n this.notify(state as Partial<DerivedState<TConfig>>);\n } else {\n this.logger.log(\"New state seems to be the same as existing, skipping\");\n }\n }\n\n @trackStateChange\n public async setInstanceState(\n key: string,\n state: Partial<DerivedInstanceState<TConfig>>\n ): Promise<void> {\n this.logger\n .withTag(key)\n .log(\"Request to update instance state, update:\", state);\n const currentState = this.instances.get(key) || this.defaultInstanceState;\n const update = { ...currentState, ...state };\n if (!deepEqual(currentState, update)) {\n this.logger\n .withTag(key)\n .log(\"Instance state update is different, updating and notifying.\");\n this.instances.set(key, update);\n this.notify(state as Partial<DerivedState<TConfig>>, key);\n } else {\n this.logger\n .withTag(key)\n .log(\"Instance state update is not different, skipping update.\");\n }\n }\n\n // If we pass in specific state to persist, it only persists that state.\n // Otherwise persists all of the worker state.\n private async persist(\n state?: Partial<DerivedServiceState<TConfig>>\n ): Promise<void> {\n this.logger.log(\"Persisting state\");\n let wasPersisted = false;\n for (const key in state || this.serviceState) {\n const item = this.config[key] as ConfigItem<any>;\n const persistence = item.persist || \"none\";\n const value = state\n ? state[key as keyof DerivedServiceState<TConfig>]\n : this.serviceState[key];\n switch (persistence) {\n case \"session\":\n await browser.storage.session.set({\n [this.storagePrefix + (key as string)]: value,\n });\n wasPersisted = true;\n break;\n case \"local\":\n await browser.storage.local.set({\n [this.storagePrefix + (key as string)]: value,\n });\n wasPersisted = true;\n break;\n default:\n break;\n }\n }\n if (wasPersisted) {\n this.logger.log(\"State was persisted\");\n } else {\n this.logger.log(\"Nothing to persist\");\n }\n }\n\n public async clear(): Promise<void> {\n this.logger.log(\"Clearing state\");\n this.serviceState = this.defaultServiceState;\n this.instances.forEach((_, key) => {\n this.instances.set(key, this.defaultInstanceState);\n });\n await this.persist();\n this.notify({});\n }\n\n public subscribe(\n listener: (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n ): void {\n this.logger.log(\"Subscribing to state\");\n this.stateChangeListeners.push(listener);\n }\n\n // Right now we notify the instance even if the state change came from the instance.\n // This should probably be skipped for instance state, since it already knows.\n private notify(changes: Partial<DerivedState<TConfig>>, key?: string): void {\n const agent = key ? this.porter.getAgentById(key) : undefined;\n const state = key ? this.get(key) : this.get();\n\n if (this.stateChangeListeners.length > 0) {\n this.logger.log(\"Notifying state change listeners in source\");\n this.stateChangeListeners.forEach((listener) => {\n listener(state, changes, agent?.info);\n });\n }\n\n if (key && agent?.info.location) {\n this.logger.withTag(key).log(\"Notifying of state change.\");\n this.porter.post(\n { action: \"stateUpdate\", payload: { state: changes } },\n agent.info.location\n );\n } else {\n this.logger.log(\"Notifying everyone\");\n // for every key of this.instances, post the state update to the corresponding key\n this.instances.forEach((_, key) => {\n this.porter.post(\n { action: \"stateUpdate\", payload: { state: changes } },\n key\n );\n });\n }\n }\n\n public get(): DerivedState<TConfig>;\n public get(\n key: string\n ): DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>;\n public get(\n key?: string\n ): DerivedServiceState<TConfig> | DerivedState<TConfig> {\n if (!key) {\n return { ...this.serviceState, ...({} as DerivedInstanceState<TConfig>) };\n }\n return { ...this.serviceState, ...this.instances.get(key) };\n }\n\n // Todo: Should we return the instance data? What is the point of this.\n public findInstance(location: BrowserLocation): string | null {\n const agent = this.porter.getAgentByLocation(location);\n if (!agent) {\n this.logger.log(\"Could not find agent for location:\", { location });\n return null;\n }\n for (const [key, instance] of this.instances) {\n if (key === agent.info.id) {\n this.logger.log(\"Found instance for key:\", key);\n return key;\n }\n }\n this.logger.log(\"Could not find instance for context and location:\", {\n location,\n });\n return null;\n }\n\n // Convenience re-export of the porter-source queryAgents method.\n public queryAgents(query: Partial<BrowserLocation>): Agent[] {\n return this.porter.queryAgents(query);\n }\n\n public async set(state: Partial<DerivedServiceState<TConfig>>): Promise<void>;\n public async set(\n state: Partial<DerivedInstanceState<TConfig>>,\n key: string\n ): Promise<void>;\n public async set(\n state: Partial<DerivedState<TConfig>>,\n key?: string\n ): Promise<void> {\n const instance = {} as Partial<DerivedInstanceState<TConfig>>;\n const worker = {} as Partial<DerivedServiceState<TConfig>>;\n\n for (const itemKey in state) {\n const item = this.config[itemKey as keyof TConfig];\n if (isConfigItem(item)) {\n if (item.partition === \"instance\") {\n const instanceItemKey =\n itemKey as keyof DerivedInstanceState<TConfig>;\n const instanceState = state as Partial<DerivedInstanceState<TConfig>>;\n instance[instanceItemKey] = instanceState[instanceItemKey];\n } else if (!item.partition || item.partition === Partition.Service) {\n const serviceItemKey = itemKey as keyof DerivedServiceState<TConfig>;\n const serviceState = state as Partial<DerivedServiceState<TConfig>>;\n worker[serviceItemKey] = serviceState[serviceItemKey]!;\n }\n }\n }\n\n if (key && Object.keys(instance).length > 0) {\n this.logger.withTag(key).log(\"Setting instance state:\", instance);\n this.setInstanceState(key, instance);\n }\n if (Object.keys(worker).length > 0) {\n this.logger.log(\"Setting service state:\", worker);\n this.setServiceState(worker);\n }\n }\n\n private async hydrate(): Promise<void> {\n this.logger.log(\"Hydrating state from storage.\");\n const local = await browser.storage.local.get(null);\n const session = await browser.storage.session.get(null);\n const combined = { ...local, ...session };\n const update: Partial<DerivedServiceState<TConfig>> = {}; // Cast update as Partial<DerivedState<TConfig>>\n let hadItems = false;\n for (const prefixedKey in combined) {\n const key = this.removePrefix(prefixedKey);\n if (this.config.hasOwnProperty(key)) {\n const value = combined[key];\n update[key as keyof DerivedServiceState<TConfig>] = value;\n hadItems = true;\n }\n }\n if (hadItems) {\n this.logger.log(\"Hydrated some items.\");\n } else {\n this.logger.log(\"No items found in storage.\");\n }\n this.serviceState = { ...this.defaultServiceState, ...update };\n }\n\n private removePrefix(key: string): string {\n if (key.startsWith(this.storagePrefix)) {\n return key.replace(this.storagePrefix, \"\");\n }\n return key;\n }\n\n private initializeInstanceDefault(): DerivedInstanceState<TConfig> {\n const instanceState: any = {};\n Object.keys(this.config).forEach((key) => {\n const item = this.config[key];\n if (isStateItem(item) && item.partition === \"instance\") {\n instanceState[key] = item.default;\n }\n });\n return instanceState;\n }\n\n private initializeServiceDefault(): DerivedServiceState<TConfig> {\n const serviceState: any = {};\n Object.keys(this.config).forEach((key) => {\n const item = this.config[key];\n if (\n isStateItem(item) &&\n (!item.partition || item.partition === Partition.Service)\n ) {\n serviceState[key] = item.default;\n }\n });\n return serviceState;\n }\n\n public subscribeToInstanceReady(\n listener: (instanceId: string, agent: AgentInfo) => void\n ): () => void {\n this.logger.log(\"Subscribing to instance ready events\");\n this.instanceReadyListeners.push(listener);\n\n this.instances.forEach((_, instanceId) => {\n const agent = this.porter.getAgentById(instanceId);\n if (agent?.info) {\n listener(instanceId, agent.info);\n }\n });\n\n return () => {\n this.logger.log(\"Unsubscribing from instance ready events\");\n const index = this.instanceReadyListeners.indexOf(listener);\n if (index !== -1) {\n this.instanceReadyListeners.splice(index, 1);\n }\n };\n }\n\n private notifyInstanceReady(instanceId: string, info: AgentInfo): void {\n if (this.instanceReadyListeners.length > 0) {\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Notifying instance ready listeners\");\n this.instanceReadyListeners.forEach((listener) => {\n listener(instanceId, info);\n });\n }\n }\n\n private extractActions(\n config: TConfig\n ): Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>> {\n return Object.entries(config)\n .filter(([_, value]) => isActionItem(value))\n .reduce<\n Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>\n >((acc, [key, value]) => {\n const action = value as ActionDefinition<\n DerivedState<TConfig>,\n any[],\n any\n >;\n return {\n ...acc,\n [key]: action,\n };\n }, {});\n }\n}\n\n// Define an interface for the API returned by create()\nexport interface CrannAPI<TConfig extends AnyConfig> {\n get: {\n (): DerivedState<TConfig>;\n (key: string): DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>;\n };\n set: {\n (state: Partial<DerivedServiceState<TConfig>>): Promise<void>;\n (\n state: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n key: string\n ): Promise<void>;\n };\n subscribe: (\n listener: (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n ) => void;\n onInstanceReady: (\n listener: (instanceId: string, agent: AgentInfo) => void\n ) => () => void;\n findInstance: (location: BrowserLocation) => string | null;\n queryAgents: (query: Partial<BrowserLocation>) => Agent[];\n clear: () => Promise<void>;\n}\n\nexport function create<TConfig extends AnyConfig>(\n config: TConfig,\n options?: CrannOptions\n): CrannAPI<TConfig> {\n const instance = Crann.getInstance(config, options);\n\n return {\n get: instance.get.bind(instance),\n set: instance.set.bind(instance),\n subscribe: instance.subscribe.bind(instance),\n onInstanceReady: instance.subscribeToInstanceReady.bind(instance),\n findInstance: instance.findInstance.bind(instance),\n queryAgents: instance.queryAgents.bind(instance),\n clear: instance.clear.bind(instance),\n };\n}\n\nfunction isConfigItem(item: any): item is ConfigItem<any> {\n return item && typeof item === \"object\" && \"default\" in item;\n}\n", "import { AgentInfo, BrowserLocation } from \"porter-source\";\n\nexport const Partition = {\n Instance: \"instance\" as const,\n Service: \"service\" as const,\n};\n\nexport const Persistence = {\n Session: \"session\" as const,\n Local: \"local\" as const,\n None: \"none\" as const,\n};\n\nexport type ActionHandler<TState, TArgs extends any[], TResult> = (\n state: TState,\n setState: (newState: Partial<TState>) => Promise<void>,\n target: BrowserLocation,\n ...args: TArgs\n) => Promise<TResult>;\n\nexport type ActionDefinition<TState, TArgs extends any[], TResult> = {\n handler: ActionHandler<TState, TArgs, TResult>;\n validate?: (...args: TArgs) => void;\n};\n\nexport type ActionsConfig<TState> = {\n [K: string]: ActionDefinition<TState, any[], Partial<TState>>;\n};\n\n// Input types (what users provide in their config)\nexport type ConfigItem<T> = {\n default: T;\n partition?: (typeof Partition)[keyof typeof Partition];\n persist?: (typeof Persistence)[keyof typeof Persistence];\n};\n\nexport type AnyConfig = Record<\n string,\n ConfigItem<any> | ActionDefinition<any, any[], any>\n>;\n\n// Helper type to extract just the state items from a config\nexport type StateConfig<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> ? T[P] : never;\n};\n\n// Helper type to extract just the action items from a config\nexport type ActionConfig<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ActionDefinition<any, any[], any> ? T[P] : never;\n};\n\n// Update DerivedState to use the internal types\nexport type DerivedState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> ? T[P][\"default\"] : never;\n};\n\n// Update DerivedInstanceState to use the internal types\nexport type DerivedInstanceState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> & { partition: \"instance\" }\n ? T[P][\"default\"]\n : never;\n};\n\n// Update DerivedServiceState to use the internal types\nexport type DerivedServiceState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> & { partition: \"service\" }\n ? T[P][\"default\"]\n : never;\n};\n\n// Type guards\nexport const isStateItem = <T>(\n item: ConfigItem<T> | ActionDefinition<any, any[], any>\n): item is ConfigItem<T> => {\n return !(\"handler\" in item);\n};\n\nexport const isActionItem = <TState, TArgs extends any[], TResult>(\n item: ConfigItem<any> | ActionDefinition<TState, TArgs, TResult>\n): item is ActionDefinition<TState, TArgs, TResult> => {\n return \"handler\" in item;\n};\n\ntype StateSubscriber<TConfig extends AnyConfig> = {\n keys?: Array<keyof DerivedState<TConfig>>;\n callback: (changes: StateUpdate<TConfig>) => void;\n};\n\ntype CrannAgent<TConfig extends AnyConfig> = {\n get: () => DerivedState<TConfig>;\n set: (update: StateUpdate<TConfig>) => void;\n subscribe: (\n callback: (changes: StateUpdate<TConfig>) => void,\n keys?: Array<keyof TConfig>\n ) => () => void;\n getAgentInfo: () => AgentInfo;\n onReady: (callback: (info: ConnectionStatus) => void) => () => void;\n};\n\ntype UseCrann<TConfig extends AnyConfig> = <\n K extends keyof DerivedState<TConfig>\n>(\n key: K\n) => [\n DerivedState<TConfig>[K],\n (value: DerivedState<TConfig>[K]) => void,\n (callback: (update: StateChangeUpdate<TConfig, K>) => void) => () => void\n];\n\ntype ConnectReturn<TConfig extends AnyConfig> = {\n useCrann: UseCrann<TConfig>;\n get: CrannAgent<TConfig>[\"get\"];\n set: CrannAgent<TConfig>[\"set\"];\n subscribe: CrannAgent<TConfig>[\"subscribe\"];\n getAgentInfo: CrannAgent<TConfig>[\"getAgentInfo\"];\n onReady: CrannAgent<TConfig>[\"onReady\"];\n callAction: (name: string, ...args: any[]) => Promise<any>;\n};\n\ntype StateChangeUpdate<\n TConfig extends AnyConfig,\n K extends keyof DerivedState<TConfig>\n> = {\n current: DerivedState<TConfig>[K];\n previous: DerivedState<TConfig>[K];\n state: DerivedState<TConfig>;\n};\n\ntype AgentSubscription<TConfig extends AnyConfig> = {\n (\n callback: (changes: StateUpdate<TConfig>) => void,\n key?: keyof DerivedState<TConfig>\n ): number;\n};\n\ntype StateUpdate<TConfig extends AnyConfig> = Partial<DerivedState<TConfig>>;\n\nexport type CrannOptions = {\n debug?: boolean;\n storagePrefix?: string;\n};\n\ntype ConnectionStatus = {\n connected: boolean;\n agent?: AgentInfo;\n};\n\nexport type CrannConfig<TState> = {\n [K: string]: ConfigItem<any> | ActionsConfig<TState>;\n};\n\nexport {\n StateSubscriber,\n CrannAgent,\n AgentSubscription,\n StateUpdate,\n DerivedState as State,\n ConnectReturn,\n UseCrann,\n ConnectionStatus,\n StateChangeUpdate,\n};\n", "export function deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n\n if (a == null || typeof a !== 'object' || b == null || typeof b !== 'object') return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n keysA.sort();\n keysB.sort();\n\n for (let i = 0; i < keysA.length; i++) {\n const key = keysA[i];\n if (key !== keysB[i] || !deepEqual(a[key], b[key])) return false;\n }\n return true;\n}", "// Create a global debug state manager\nexport class DebugManager {\n private static _debug: boolean = false;\n\n static setDebug(value: boolean): void {\n DebugManager._debug = value;\n }\n\n static isDebugEnabled(): boolean {\n return DebugManager._debug;\n }\n}\n\n// Export a convenience function\nexport function isDebugEnabled(): boolean {\n return DebugManager.isDebugEnabled();\n}\n", "import { isDebugEnabled } from \"./debug\";\n\nexport type StateChangeMetadata = {\n source: string;\n timestamp: number;\n changes: any;\n instanceKey?: string;\n};\n\nexport function trackStateChange(\n target: any,\n propertyKey: string,\n descriptor: PropertyDescriptor\n): PropertyDescriptor {\n const originalMethod = descriptor.value;\n\n descriptor.value = function (...args: any[]) {\n // Only log if debugging is enabled\n if (isDebugEnabled()) {\n // Get the stack trace to find the actual caller\n const stack = new Error().stack;\n const lines = stack?.split(\"\\n\") || [];\n const callerMatch = lines[3]?.match(/at\\s+(\\S+)\\s+/);\n const caller = callerMatch ? callerMatch[1] : \"unknown\";\n\n const changes = args.length > 1 ? args[1] : undefined;\n\n const metadata: StateChangeMetadata = {\n source: caller,\n timestamp: Date.now(),\n instanceKey: args[0],\n changes,\n };\n\n console.log(`Crann State Change:`, metadata);\n }\n return originalMethod.apply(this, args);\n };\n\n return descriptor;\n}\n", "import { source, AgentInfo, connect, Message, AgentAPI } from \"porter-source\";\nimport { createEndpoint } from \"./endpoint\";\nimport { MessageEndpoint, CallMessage, RPCMessage } from \"./types\";\nimport { ActionsConfig } from \"../model/crann.model\";\nimport { Logger } from \"../utils/logger\";\nimport { getAgentTag } from \"../utils/agent\";\n\nexport function createCrannRPCAdapter<\n TState,\n TActions extends ActionsConfig<TState>\n>(\n initialState: TState,\n actions: TActions,\n porter?: ReturnType<typeof source> | ReturnType<typeof connect>,\n setState?: (newState: Partial<TState>) => Promise<void>\n) {\n const porterInstance = porter || source(\"crann\");\n\n // Determine if this is a service worker instance (source) or content script instance (connect)\n const isServiceWorker = !(porterInstance.type === \"agent\");\n\n // Set up logger with the appropriate context\n const logger = Logger.forContext(isServiceWorker ? \"Core:RPC\" : \"Agent:RPC\");\n\n const messageEndpoint: MessageEndpoint = {\n postMessage: (message, transferables) => {\n if (isServiceWorker) {\n logger.debug(\"Posting message from service worker:\", {\n message,\n transferables,\n });\n // In service worker, we need to respond to the specific target\n const [, rpcPayload] = message;\n const target = getTargetFromMessage(rpcPayload);\n if (!target) {\n logger.warn(\"No target specified for RPC response in service worker\");\n return;\n }\n porterInstance.post(\n {\n action: \"rpc\",\n payload: {\n message,\n transferables: transferables || [],\n },\n },\n target\n );\n } else {\n // In content script (agent) context\n // Get the agent info only when needed\n const agentInfo = (porterInstance as AgentAPI).getAgentInfo();\n\n if (!agentInfo) {\n logger.warn(\"No agent info found for posting message\", { agentInfo });\n return;\n }\n\n // Get the agent tag for logging\n const myTag = getAgentTag(agentInfo);\n\n // Destructure the tuple, skipping the messageId which we don't need\n const [, rpcPayload] = message;\n\n // Use type guard to check if it's a call message\n if (\"call\" in rpcPayload) {\n // Add the target info to the call message\n rpcPayload.call.target = agentInfo?.location;\n }\n\n logger.withTag(myTag).debug(\"Sending RPC message from agent:\", {\n rpcPayload,\n message,\n });\n // In content script, target is automatically the service worker\n porterInstance.post({\n action: \"rpc\",\n payload: {\n message,\n transferables: transferables || [],\n },\n });\n }\n },\n addEventListener: (event, listener) => {\n porterInstance.on({\n rpc: (message: Message<string>, info?: AgentInfo) => {\n try {\n if (!info) {\n logger.debug(\"RPC message received:\", {\n message,\n event,\n });\n } else {\n // Get the agent tag for logging\n const myTag = getAgentTag(info);\n logger.withTag(myTag).debug(\"RPC message received:\", {\n message,\n event,\n });\n }\n\n const { payload } = message;\n const { message: originalMessage, transferables = [] } = payload;\n const rpcEvent = new MessageEvent(\"message\", {\n data: originalMessage,\n ports:\n (transferables.filter(\n (t: unknown) => t instanceof MessagePort\n ) as MessagePort[]) || [],\n });\n listener(rpcEvent);\n } catch (e) {\n logger.error(\"Failed to parse RPC message payload:\", e);\n }\n },\n });\n },\n removeEventListener: () => {\n // Porter-source doesn't support removing listeners\n },\n // Add context information\n context: {\n isServiceWorker,\n agentInfo: !isServiceWorker\n ? (porterInstance as AgentAPI).getAgentInfo()\n : undefined,\n },\n };\n\n return createEndpoint(messageEndpoint, initialState, actions, setState);\n}\n\n// Don't love this being here. Let's move it sometime soon,\n// or find another way to do this.\nfunction getTargetFromMessage(payload: RPCMessage): any {\n if (\"result\" in payload) return payload.result.target;\n if (\"error\" in payload) return payload.error.target;\n if (\"call\" in payload) return payload.call.target;\n if (\"release\" in payload) return payload.release.target;\n return undefined;\n}\n", "export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport class Logger {\n private static debug = false;\n private static prefix = \"CrannLogger\";\n private static noOp = function () {};\n\n private context: string;\n private tag: string | null = null;\n\n /**\n * Create a new Logger instance with a specific context\n */\n constructor(context: string) {\n this.context = context;\n }\n\n static setDebug(value: boolean): void {\n Logger.debug = value;\n }\n\n static setPrefix(value: string): void {\n Logger.prefix = value;\n }\n\n /**\n * Set a persistent tag for this Logger instance\n */\n setTag(tag: string | null): void {\n this.tag = tag;\n }\n\n /**\n * Create a temporary logger with a specific tag\n * This doesn't modify the original logger instance\n */\n withTag(tag: string) {\n const tempLogger = new Logger(this.context);\n tempLogger.setTag(tag);\n return tempLogger;\n }\n\n /**\n * Get the full context string including tag if present\n */\n private getFullContext(): string {\n if (this.tag) {\n return `${this.context}:${this.tag}`;\n }\n return this.context;\n }\n\n /**\n * Create the log methods bound to the current context and tag\n */\n private createLogMethods() {\n const fullContext = this.getFullContext();\n const formatString = `%c${Logger.prefix}%c [%c${fullContext}%c]`;\n\n // Styles for the prefix and context - updated for better readability on dark backgrounds\n const prefixStyle = \"color: #3fcbff; font-weight: bold\"; // Bright cyan\n const contextStyle = \"color: #d58cff; font-weight: bold\"; // Bright purple\n const resetStyle = \"\";\n\n if (Logger.debug) {\n return {\n debug: console.log.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n log: console.log.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n info: console.info.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n warn: console.warn.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n error: console.error.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n };\n } else {\n return {\n debug: Logger.noOp,\n log: Logger.noOp,\n info: Logger.noOp,\n warn: Logger.noOp,\n error: Logger.noOp,\n };\n }\n }\n\n /**\n * Log methods that are dynamically created based on current context and tag\n */\n get debug() {\n return this.createLogMethods().debug;\n }\n get log() {\n return this.createLogMethods().log;\n }\n get info() {\n return this.createLogMethods().info;\n }\n get warn() {\n return this.createLogMethods().warn;\n }\n get error() {\n return this.createLogMethods().error;\n }\n\n /**\n * Static helper to create a logger with a specific context\n */\n static forContext(context: string, tag?: string): Logger {\n const logger = new Logger(context);\n if (tag) {\n logger.setTag(tag);\n }\n return logger;\n }\n}\n", "import { AgentInfo } from \"porter-source\";\n\n/**\n * Formats an agent tag based on the agent information\n * @param agent Agent information\n * @param options Configuration options\n * @returns Formatted agent tag string\n */\nexport function getAgentTag(\n agent: AgentInfo,\n options: { terse?: boolean } = { terse: true }\n): string {\n const formatTabId = (tabId: number | string): string => {\n const tabIdStr = String(tabId);\n if (tabIdStr.length >= 4) {\n return tabIdStr.slice(-4);\n } else {\n return tabIdStr.padStart(4, \"0\");\n }\n };\n\n const formattedTabId = formatTabId(agent.location.tabId);\n\n if (options?.terse) {\n return `${formattedTabId}:${agent.location.frameId}`;\n }\n return `${agent.location.context}:${formattedTabId}:${agent.location.frameId}`;\n}\n", "import { createBasicEncoder } from \"./encoding\";\nimport type {\n MessageEndpoint,\n RemoteCallable,\n EncodingStrategy,\n EncodingStrategyApi,\n Retainer,\n CallMessage,\n ResultMessage,\n ErrorMessage,\n RPCMessage,\n} from \"./types\";\nimport { ActionsConfig } from \"../model/crann.model\";\nimport { Logger } from \"../utils/logger\";\nimport { getAgentTag } from \"../utils/agent\";\n\nconst CALL = 0;\nconst RESULT = 1;\nconst TERMINATE = 2;\nconst RELEASE = 3;\nconst FUNCTION_APPLY = 5;\nconst FUNCTION_RESULT = 6;\n\ntype AnyFunction = (...args: any[]) => any;\n\nexport interface CreateEndpointOptions<T = unknown> {\n uuid?(): string;\n createEncoder?(api: EncodingStrategyApi): EncodingStrategy;\n callable?: (keyof T)[];\n}\n\nexport interface Endpoint<T> {\n readonly call: RemoteCallable<T>;\n replace(messenger: MessageEndpoint): void;\n expose(api: Record<string, AnyFunction | undefined>): void;\n callable(...methods: string[]): void;\n terminate(): void;\n}\n\n/**\n * An endpoint wraps around a messenger, acting as the intermediary for all\n * messages both send from, and received by, that messenger. The endpoint sends\n * all messages as arrays, where the first element is the message type, and the\n * second is the arguments for that message (as an array). For messages that send\n * meaningful content across the wire (e.g., arguments to function calls, return\n * results), the endpoint first encodes these values.\n *\n * Encoding is done using a CBOR-like encoding scheme. The value is encoded into\n * an array buffer, and is paired with an additional array buffer that contains all\n * the strings used in that message (in the encoded value, strings are encoded as\n * their index in the \"strings\" encoding to reduce the cost of heavily-duplicated\n * strings, which is more likely in payloads containing UI). This encoding also takes\n * care of encoding functions: it uses a \"tagged\" item in CBOR to represent a\n * function as a string ID, which the opposite endpoint will be capable of turning\n * into a consistent, memory-manageable function proxy.\n *\n * The main CBOR encoding is entirely take from the [cbor.js package](https://github.com/paroga/cbor-js).\n * The special behavior for encoding strings and functions was then added in to the\n * encoder and decoder. For additional details on CBOR:\n *\n * @see https://tools.ietf.org/html/rfc7049\n */\nexport function createEndpoint<TState, TActions extends ActionsConfig<TState>>(\n messenger: MessageEndpoint,\n state: TState,\n actions: TActions,\n setState?: (newState: Partial<TState>) => Promise<void>,\n encodingStrategy?: EncodingStrategy\n): RemoteCallable<TActions> {\n const callbacks = new Map<number, (result: unknown) => void>();\n const retainedObjects = new Map<string, Set<Retainer>>();\n\n // Create logger - will be used in Service Worker or Agent context based on the messenger's context\n const contextPrefix = messenger.context?.isServiceWorker ? \"Core\" : \"Agent\";\n const logger = Logger.forContext(`${contextPrefix}:RPC`);\n\n // If we have agent info, set the tag\n if (messenger.context?.agentInfo) {\n logger.setTag(getAgentTag(messenger.context.agentInfo));\n }\n\n messenger.addEventListener(\"message\", (event) => {\n logger.debug(\"Message received:\", event);\n const [id, message] = event.data as [number, RPCMessage];\n\n if (\"call\" in message && \"args\" in message.call) {\n logger.debug(\"Processing call message:\", message);\n const callMessage = message.call;\n const { id: callId, args, target } = callMessage;\n const action = actions[callId];\n if (!action) {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: \"Action not found\", target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n return;\n }\n\n try {\n if (action.validate) {\n action.validate(...args);\n }\n\n // Ensure we have a target - if not provided, we need to handle this case\n if (!target) {\n messenger.postMessage([\n id,\n {\n error: {\n id: callId,\n error: \"No target provided for action call\",\n target,\n },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n return;\n }\n\n // Handle both synchronous and asynchronous results\n Promise.resolve(action.handler(state, setState!, target, ...args)).then(\n (result: unknown) => {\n logger.debug(\"Action handler result:\", {\n result,\n target,\n });\n messenger.postMessage([\n id,\n { result: { id: callId, result, target } },\n ] as [number, ResultMessage]);\n },\n (error: Error) => {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: error.message, target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n }\n );\n } catch (error) {\n if (error instanceof Error) {\n messenger.postMessage([\n id,\n { error: { id: callId, error: error.message, target } },\n ] as [number, ErrorMessage]);\n } else {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: \"Unknown error occurred\", target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n }\n }\n } else if (\"result\" in message) {\n const resultMessage = message.result;\n const callback = callbacks.get(id);\n if (callback) {\n callback(resultMessage.result);\n callbacks.delete(id);\n }\n } else if (\"error\" in message) {\n const errorMessage = message.error;\n const callback = callbacks.get(id);\n if (callback) {\n callback(Promise.reject(new Error(errorMessage.error)));\n callbacks.delete(id);\n }\n } else if (\"release\" in message) {\n const releaseMessage = message.release;\n const retainers = retainedObjects.get(releaseMessage.id);\n if (retainers) {\n retainers.clear();\n retainedObjects.delete(releaseMessage.id);\n }\n }\n });\n\n const proxy = new Proxy({} as RemoteCallable<TActions>, {\n get(_, prop: string) {\n return (...args: unknown[]) => {\n const id = Math.random();\n return new Promise((resolve, reject) => {\n callbacks.set(id, (result) => {\n if (result instanceof Promise) {\n result.then(resolve, reject);\n } else {\n resolve(result);\n }\n });\n messenger.postMessage([id, { call: { id: prop, args } }] as [\n number,\n CallMessage\n ]);\n });\n };\n },\n });\n\n return proxy;\n}\n\nfunction defaultUuid() {\n return `${uuidSegment()}-${uuidSegment()}-${uuidSegment()}-${uuidSegment()}`;\n}\n\nfunction uuidSegment() {\n return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16);\n}\n\nfunction createCallable<T>(\n handlerForCall: (\n property: string | number | symbol\n ) => AnyFunction | undefined,\n callable?: (keyof T)[]\n): RemoteCallable<T> {\n let call: any;\n\n if (callable == null) {\n if (typeof Proxy !== \"function\") {\n throw new Error(\n `You must pass an array of callable methods in environments without Proxies.`\n );\n }\n\n const cache = new Map<string | number | symbol, AnyFunction | undefined>();\n\n call = new Proxy(\n {},\n {\n get(_target, property) {\n if (cache.has(property)) {\n return cache.get(property);\n }\n\n const handler = handlerForCall(property);\n cache.set(property, handler);\n return handler;\n },\n }\n );\n } else {\n call = {};\n\n for (const method of callable) {\n Object.defineProperty(call, method, {\n value: handlerForCall(method),\n writable: false,\n configurable: true,\n enumerable: true,\n });\n }\n }\n\n return call;\n}\n", "import {\n ConfigItem,\n DerivedState,\n StateSubscriber,\n ConnectReturn,\n UseCrann,\n ConnectionStatus,\n StateChangeUpdate,\n ActionDefinition,\n AnyConfig,\n isStateItem,\n isActionItem,\n} from \"./model/crann.model\";\nimport { AgentInfo, connect as connectPorter } from \"porter-source\";\nimport { createCrannRPCAdapter } from \"./rpc/adapter\";\nimport { Logger } from \"./utils/logger\";\nimport { getAgentTag } from \"./utils/agent\";\n\nlet connectionStatus: ConnectionStatus = { connected: false };\nlet crannInstance: unknown = null;\n\nexport function connect<TConfig extends AnyConfig>(\n config: TConfig,\n options?: { context?: string; debug?: boolean }\n): ConnectReturn<TConfig> {\n const debug = options?.debug || false;\n const context = options?.context;\n\n // Set up logger\n if (debug) {\n Logger.setDebug(true);\n }\n const logger = Logger.forContext(\"Agent\");\n\n let _myInfo: AgentInfo;\n let _myTag = \"unset\";\n const readyCallbacks = new Set<(info: ConnectionStatus) => void>();\n\n logger.log(\n \"Initializing Crann Agent\" + (context ? ` with context: ${context}` : \"\")\n );\n if (crannInstance) {\n logger.log(\"We had an instance already, returning\");\n\n if (connectionStatus.connected) {\n logger.log(\"Connect, calling onReady callback\");\n setTimeout(() => {\n readyCallbacks.forEach((callback) => callback(connectionStatus));\n }, 0);\n }\n return crannInstance as ConnectReturn<TConfig>;\n }\n\n logger.log(\"No existing instance, creating a new one\");\n const porter = connectPorter({\n namespace: \"crann\",\n debug: false,\n });\n\n logger.log(\"Porter connection created\");\n\n // Initialize RPC with empty actions since this is the client side\n const actions = Object.entries(config)\n .filter(([_, value]) => isActionItem(value))\n .reduce<\n Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>\n >((acc, [key, value]) => {\n const action = value as ActionDefinition<\n DerivedState<TConfig>,\n any[],\n any\n >;\n return {\n ...acc,\n [key]: {\n type: \"action\",\n handler: action.handler,\n validate: action.validate,\n },\n };\n }, {});\n\n const rpcEndpoint = createCrannRPCAdapter(\n getDerivedState(config),\n actions,\n porter\n );\n\n let initialStateReceived = false;\n\n porter.on({\n initialState: (message) => {\n logger.log(\"initialState received\", {\n alreadyReceived: initialStateReceived,\n payload: message.payload,\n });\n\n if (initialStateReceived) {\n logger.log(\"Ignoring duplicate initialState message\");\n return;\n }\n\n initialStateReceived = true;\n\n _state = message.payload.state;\n _myInfo = message.payload.info;\n _myTag = getAgentTag(_myInfo);\n connectionStatus = { connected: true, agent: _myInfo };\n\n // Update logger with the agent tag once we have it\n logger.setTag(_myTag);\n logger.log(\n `Initial state received and ${listeners.size} listeners notified`,\n {\n message,\n }\n );\n readyCallbacks.forEach((callback) => {\n logger.log(\"Calling onReady callbacks\");\n callback(connectionStatus);\n });\n listeners.forEach((listener) => {\n listener.callback(_state);\n });\n },\n stateUpdate: (message) => {\n changes = message.payload.state;\n _state = { ..._state, ...changes };\n logger.log(\"State updated:\", { message, changes, _state });\n if (!changes) return;\n\n listeners.forEach((listener) => {\n if (listener.keys === undefined) {\n listener.callback(changes!);\n } else {\n const matchFound = listener.keys.some((key) => key in changes!);\n if (matchFound) {\n listener.callback(changes!);\n }\n }\n });\n },\n });\n logger.log(\"Porter connected. Setting up state and listeners\");\n let _state = getDerivedState(config);\n let changes: Partial<DerivedState<TConfig>> | null = null;\n const listeners = new Set<StateSubscriber<TConfig>>();\n\n logger.log(\"Completed setup, returning instance\");\n\n const get = () => _state;\n const set = (newState: Partial<DerivedState<TConfig>>) => {\n logger.log(\"Calling post with setState\", newState);\n porter.post({ action: \"setState\", payload: { state: newState } });\n };\n\n const subscribe = (\n callback: (changes: Partial<DerivedState<TConfig>>) => void,\n keys?: Array<keyof DerivedState<TConfig>>\n ): (() => void) => {\n const listener = { keys, callback };\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n };\n\n const useCrann: UseCrann<TConfig> = <K extends keyof DerivedState<TConfig>>(\n key: K\n ) => {\n const getValue = () => {\n const value = get()[key];\n return value as TConfig[K] extends ConfigItem<any>\n ? TConfig[K][\"default\"]\n : never;\n };\n\n const setValue = (\n value: TConfig[K] extends ConfigItem<any> ? TConfig[K][\"default\"] : never\n ) => set({ [key]: value } as Partial<DerivedState<TConfig>>);\n\n const subscribeToChanges = (\n callback: (update: StateChangeUpdate<TConfig, K>) => void\n ) => {\n let previousValue = getValue();\n\n return subscribe(\n (changes) => {\n if (key in changes) {\n const currentValue = getValue();\n const fullState = get();\n callback({\n current: currentValue,\n previous: previousValue,\n state: fullState,\n } as StateChangeUpdate<TConfig, K>);\n previousValue = currentValue;\n }\n },\n [key]\n );\n };\n\n return [getValue(), setValue, subscribeToChanges];\n };\n\n const onReady = (callback: (info: ConnectionStatus) => void) => {\n logger.log(\"onReady callback added\");\n readyCallbacks.add(callback);\n if (connectionStatus.connected) {\n logger.log(\"calling onReady callback\");\n setTimeout(() => {\n callback(connectionStatus);\n }, 0);\n }\n return () => readyCallbacks.delete(callback);\n };\n\n const getAgentInfo = () => _myInfo;\n\n const callAction = async (name: string, ...args: any[]) => {\n logger.log(\"Calling action\", name, args);\n return (rpcEndpoint as any)[name](...args);\n };\n\n const instance = {\n useCrann,\n get,\n set,\n subscribe,\n getAgentInfo,\n onReady,\n callAction,\n };\n\n crannInstance = instance;\n\n return crannInstance as ConnectReturn<TConfig>;\n}\n\nexport function connected(): boolean {\n return crannInstance !== null;\n}\n\nfunction getDerivedState<TConfig extends AnyConfig>(\n config: TConfig\n): DerivedState<TConfig> {\n const state: any = {};\n Object.keys(config).forEach((key) => {\n const item = config[key];\n if (isStateItem(item)) {\n state[key] = item.default;\n }\n });\n return state;\n}\n", "import { useState, useEffect, useCallback, useMemo, useRef } from \"react\";\nimport { ConfigItem, DerivedState, StateUpdate } from \"../model/crann.model\";\nimport { connect } from \"../crannAgent\";\n\nexport function createCrannStateHook<\n TConfig extends Record<string, ConfigItem<any>>\n>(config: TConfig) {\n return function useCrannState(context?: string) {\n const { useCrann, get, set, subscribe, callAction } = useMemo(() => {\n const instance = connect(config);\n return instance;\n }, [context]);\n\n const useStateItem = useCallback(\n <K extends keyof DerivedState<TConfig>>(key: K) => {\n const [value, setValue] = useState<DerivedState<TConfig>[K]>(\n get()[key]\n );\n const valueRef = useRef(value);\n\n useEffect(() => {\n valueRef.current = value;\n }, [value]);\n\n useEffect(() => {\n setValue(get()[key]);\n const unsubscribe = subscribe(\n (changes: StateUpdate<TConfig>) => {\n if (key in changes) {\n setValue(changes[key] as DerivedState<TConfig>[K]);\n }\n },\n [key]\n );\n return unsubscribe;\n }, [key]);\n\n const updateValue = useCallback(\n (newValue: DerivedState<TConfig>[K]) => {\n set({ [key]: newValue } as Partial<DerivedState<TConfig>>);\n },\n [key]\n );\n\n return [value, updateValue] as const;\n },\n [get, set, subscribe]\n );\n\n const getState = useCallback(() => get(), [get]);\n\n const setState = useCallback(\n (newState: Partial<DerivedState<TConfig>>) => {\n set(newState);\n },\n [set]\n );\n\n return {\n useStateItem,\n getState,\n setState,\n useCrann,\n callAction,\n };\n };\n}\n"],
5
- "mappings": "usBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,WAAAE,EAAA,cAAAC,EAAA,gBAAAC,EAAA,YAAAC,EAAA,cAAAC,GAAA,WAAAC,GAAA,yBAAAC,KAAA,eAAAC,GAAAT,ICAA,IAAAU,EAAoB,qCCEb,IAAMC,EAAY,CACvB,SAAU,WACV,QAAS,SACX,EAEaC,EAAc,CACzB,QAAS,UACT,MAAO,QACP,KAAM,MACR,EA4DaC,EACXC,GAEO,EAAE,YAAaA,GAGXC,EACXD,GAEO,YAAaA,EDnEtB,IAAAE,GAAyC,yBEblC,SAASC,EAAUC,EAAQC,EAAiB,CAC/C,GAAID,IAAMC,EAAG,MAAO,GAEpB,GAAID,GAAK,MAAQ,OAAOA,GAAM,UAAYC,GAAK,MAAQ,OAAOA,GAAM,SAAU,MAAO,GAErF,IAAMC,EAAQ,OAAO,KAAKF,CAAC,EACrBG,EAAQ,OAAO,KAAKF,CAAC,EAE3B,GAAIC,EAAM,SAAWC,EAAM,OAAQ,MAAO,GAE1CD,EAAM,KAAK,EACXC,EAAM,KAAK,EAEX,QAAS,EAAI,EAAG,EAAID,EAAM,OAAQ,IAAK,CACnC,IAAME,EAAMF,EAAM,CAAC,EACnB,GAAIE,IAAQD,EAAM,CAAC,GAAK,CAACJ,EAAUC,EAAEI,CAAG,EAAGH,EAAEG,CAAG,CAAC,EAAG,MAAO,EAC/D,CACA,MAAO,EACX,CCjBO,IAAMC,EAAN,MAAMA,CAAa,CAGxB,OAAO,SAASC,EAAsB,CACpCD,EAAa,OAASC,CACxB,CAEA,OAAO,gBAA0B,CAC/B,OAAOD,EAAa,MACtB,CACF,EAVaA,EACI,OAAkB,GAD5B,IAAME,EAANF,EAaA,SAASG,GAA0B,CACxC,OAAOD,EAAa,eAAe,CACrC,CCPO,SAASE,EACdC,EACAC,EACAC,EACoB,CACpB,IAAMC,EAAiBD,EAAW,MAElC,OAAAA,EAAW,MAAQ,YAAaE,EAAa,CAhB/C,IAAAC,EAkBI,GAAIC,EAAe,EAAG,CAEpB,IAAMC,EAAQ,IAAI,MAAM,EAAE,MAEpBC,GAAcH,IADNE,GAAA,YAAAA,EAAO,MAAM;AAAA,KAAS,CAAC,GACX,CAAC,IAAP,YAAAF,EAAU,MAAM,iBAC9BI,EAASD,EAAcA,EAAY,CAAC,EAAI,UAExCE,EAAUN,EAAK,OAAS,EAAIA,EAAK,CAAC,EAAI,OAEtCO,EAAgC,CACpC,OAAQF,EACR,UAAW,KAAK,IAAI,EACpB,YAAaL,EAAK,CAAC,EACnB,QAAAM,CACF,EAEA,QAAQ,IAAI,sBAAuBC,CAAQ,CAC7C,CACA,OAAOR,EAAe,MAAM,KAAMC,CAAI,CACxC,EAEOF,CACT,CCxCA,IAAAU,EAA8D,yBCEvD,IAAMC,EAAN,MAAMA,CAAO,CAWlB,YAAYC,EAAiB,CAL7B,KAAQ,IAAqB,KAM3B,KAAK,QAAUA,CACjB,CAEA,OAAO,SAASC,EAAsB,CACpCF,EAAO,MAAQE,CACjB,CAEA,OAAO,UAAUA,EAAqB,CACpCF,EAAO,OAASE,CAClB,CAKA,OAAOC,EAA0B,CAC/B,KAAK,IAAMA,CACb,CAMA,QAAQA,EAAa,CACnB,IAAMC,EAAa,IAAIJ,EAAO,KAAK,OAAO,EAC1C,OAAAI,EAAW,OAAOD,CAAG,EACdC,CACT,CAKQ,gBAAyB,CAC/B,OAAI,KAAK,IACA,GAAG,KAAK,OAAO,IAAI,KAAK,GAAG,GAE7B,KAAK,OACd,CAKQ,kBAAmB,CACzB,IAAMC,EAAc,KAAK,eAAe,EAClCC,EAAe,KAAKN,EAAO,MAAM,SAASK,CAAW,MAGrDE,EAAc,oCACdC,EAAe,oCACfC,EAAa,GAEnB,OAAIT,EAAO,MACF,CACL,MAAO,QAAQ,IAAI,KACjB,QACAM,EACAC,EACAE,EACAD,EACAC,CACF,EACA,IAAK,QAAQ,IAAI,KACf,QACAH,EACAC,EACAE,EACAD,EACAC,CACF,EACA,KAAM,QAAQ,KAAK,KACjB,QACAH,EACAC,EACAE,EACAD,EACAC,CACF,EACA,KAAM,QAAQ,KAAK,KACjB,QACAH,EACAC,EACAE,EACAD,EACAC,CACF,EACA,MAAO,QAAQ,MAAM,KACnB,QACAH,EACAC,EACAE,EACAD,EACAC,CACF,CACF,EAEO,CACL,MAAOT,EAAO,KACd,IAAKA,EAAO,KACZ,KAAMA,EAAO,KACb,KAAMA,EAAO,KACb,MAAOA,EAAO,IAChB,CAEJ,CAKA,IAAI,OAAQ,CACV,OAAO,KAAK,iBAAiB,EAAE,KACjC,CACA,IAAI,KAAM,CACR,OAAO,KAAK,iBAAiB,EAAE,GACjC,CACA,IAAI,MAAO,CACT,OAAO,KAAK,iBAAiB,EAAE,IACjC,CACA,IAAI,MAAO,CACT,OAAO,KAAK,iBAAiB,EAAE,IACjC,CACA,IAAI,OAAQ,CACV,OAAO,KAAK,iBAAiB,EAAE,KACjC,CAKA,OAAO,WAAWC,EAAiBE,EAAsB,CACvD,IAAMO,EAAS,IAAIV,EAAOC,CAAO,EACjC,OAAIE,GACFO,EAAO,OAAOP,CAAG,EAEZO,CACT,CACF,EAjJaV,EACI,MAAQ,GADZA,EAEI,OAAS,cAFbA,EAGI,KAAO,UAAY,CAAC,EAH9B,IAAMW,EAANX,ECMA,SAASY,EACdC,EACAC,EAA+B,CAAE,MAAO,EAAK,EACrC,CAUR,IAAMC,GATeC,GAAmC,CACtD,IAAMC,EAAW,OAAOD,CAAK,EAC7B,OAAIC,EAAS,QAAU,EACdA,EAAS,MAAM,EAAE,EAEjBA,EAAS,SAAS,EAAG,GAAG,CAEnC,GAEmCJ,EAAM,SAAS,KAAK,EAEvD,OAAIC,GAAA,MAAAA,EAAS,MACJ,GAAGC,CAAc,IAAIF,EAAM,SAAS,OAAO,GAE7C,GAAGA,EAAM,SAAS,OAAO,IAAIE,CAAc,IAAIF,EAAM,SAAS,OAAO,EAC9E,CCmCO,SAASK,EACdC,EACAC,EACAC,EACAC,EACAC,EAC0B,CApE5B,IAAAC,EAAAC,EAqEE,IAAMC,EAAY,IAAI,IAChBC,EAAkB,IAAI,IAGtBC,GAAgBJ,EAAAL,EAAU,UAAV,MAAAK,EAAmB,gBAAkB,OAAS,QAC9DK,EAASC,EAAO,WAAW,GAAGF,CAAa,MAAM,EAGvD,OAAIH,EAAAN,EAAU,UAAV,MAAAM,EAAmB,WACrBI,EAAO,OAAOE,EAAYZ,EAAU,QAAQ,SAAS,CAAC,EAGxDA,EAAU,iBAAiB,UAAYa,GAAU,CAC/CH,EAAO,MAAM,oBAAqBG,CAAK,EACvC,GAAM,CAACC,EAAIC,CAAO,EAAIF,EAAM,KAE5B,GAAI,SAAUE,GAAW,SAAUA,EAAQ,KAAM,CAC/CL,EAAO,MAAM,2BAA4BK,CAAO,EAChD,IAAMC,EAAcD,EAAQ,KACtB,CAAE,GAAIE,EAAQ,KAAAC,EAAM,OAAAC,CAAO,EAAIH,EAC/BI,EAASlB,EAAQe,CAAM,EAC7B,GAAI,CAACG,EAAQ,CACXpB,EAAU,YAAY,CACpBc,EACA,CACE,MAAO,CAAE,GAAIG,EAAQ,MAAO,mBAAoB,OAAAE,CAAO,CACzD,CACF,CAA2B,EAC3B,MACF,CAEA,GAAI,CAMF,GALIC,EAAO,UACTA,EAAO,SAAS,GAAGF,CAAI,EAIrB,CAACC,EAAQ,CACXnB,EAAU,YAAY,CACpBc,EACA,CACE,MAAO,CACL,GAAIG,EACJ,MAAO,qCACP,OAAAE,CACF,CACF,CACF,CAA2B,EAC3B,MACF,CAGA,QAAQ,QAAQC,EAAO,QAAQnB,EAAOE,EAAWgB,EAAQ,GAAGD,CAAI,CAAC,EAAE,KAChEG,GAAoB,CACnBX,EAAO,MAAM,yBAA0B,CACrC,OAAAW,EACA,OAAAF,CACF,CAAC,EACDnB,EAAU,YAAY,CACpBc,EACA,CAAE,OAAQ,CAAE,GAAIG,EAAQ,OAAAI,EAAQ,OAAAF,CAAO,CAAE,CAC3C,CAA4B,CAC9B,EACCG,GAAiB,CAChBtB,EAAU,YAAY,CACpBc,EACA,CACE,MAAO,CAAE,GAAIG,EAAQ,MAAOK,EAAM,QAAS,OAAAH,CAAO,CACpD,CACF,CAA2B,CAC7B,CACF,CACF,OAASG,EAAO,CACVA,aAAiB,MACnBtB,EAAU,YAAY,CACpBc,EACA,CAAE,MAAO,CAAE,GAAIG,EAAQ,MAAOK,EAAM,QAAS,OAAAH,CAAO,CAAE,CACxD,CAA2B,EAE3BnB,EAAU,YAAY,CACpBc,EACA,CACE,MAAO,CAAE,GAAIG,EAAQ,MAAO,yBAA0B,OAAAE,CAAO,CAC/D,CACF,CAA2B,CAE/B,CACF,SAAW,WAAYJ,EAAS,CAC9B,IAAMQ,EAAgBR,EAAQ,OACxBS,EAAWjB,EAAU,IAAIO,CAAE,EAC7BU,IACFA,EAASD,EAAc,MAAM,EAC7BhB,EAAU,OAAOO,CAAE,EAEvB,SAAW,UAAWC,EAAS,CAC7B,IAAMU,EAAeV,EAAQ,MACvBS,EAAWjB,EAAU,IAAIO,CAAE,EAC7BU,IACFA,EAAS,QAAQ,OAAO,IAAI,MAAMC,EAAa,KAAK,CAAC,CAAC,EACtDlB,EAAU,OAAOO,CAAE,EAEvB,SAAW,YAAaC,EAAS,CAC/B,IAAMW,EAAiBX,EAAQ,QACzBY,EAAYnB,EAAgB,IAAIkB,EAAe,EAAE,EACnDC,IACFA,EAAU,MAAM,EAChBnB,EAAgB,OAAOkB,EAAe,EAAE,EAE5C,CACF,CAAC,EAEa,IAAI,MAAM,CAAC,EAA+B,CACtD,IAAIE,EAAGC,EAAc,CACnB,MAAO,IAAIX,IAAoB,CAC7B,IAAMJ,EAAK,KAAK,OAAO,EACvB,OAAO,IAAI,QAAQ,CAACgB,EAASC,IAAW,CACtCxB,EAAU,IAAIO,EAAKO,GAAW,CACxBA,aAAkB,QACpBA,EAAO,KAAKS,EAASC,CAAM,EAE3BD,EAAQT,CAAM,CAElB,CAAC,EACDrB,EAAU,YAAY,CAACc,EAAI,CAAE,KAAM,CAAE,GAAIe,EAAM,KAAAX,CAAK,CAAE,CAAC,CAGtD,CACH,CAAC,CACH,CACF,CACF,CAAC,CAGH,CHnMO,SAASc,EAIdC,EACAC,EACAC,EACAC,EACA,CACA,IAAMC,EAAiBF,MAAU,UAAO,OAAO,EAGzCG,EAAoBD,EAAe,OAAS,QAG5CE,EAASC,EAAO,WAAWF,EAAkB,WAAa,WAAW,EAErEG,EAAmC,CACvC,YAAa,CAACC,EAASC,IAAkB,CACvC,GAAIL,EAAiB,CACnBC,EAAO,MAAM,uCAAwC,CACnD,QAAAG,EACA,cAAAC,CACF,CAAC,EAED,GAAM,CAAC,CAAEC,CAAU,EAAIF,EACjBG,EAASC,GAAqBF,CAAU,EAC9C,GAAI,CAACC,EAAQ,CACXN,EAAO,KAAK,wDAAwD,EACpE,MACF,CACAF,EAAe,KACb,CACE,OAAQ,MACR,QAAS,CACP,QAAAK,EACA,cAAeC,GAAiB,CAAC,CACnC,CACF,EACAE,CACF,CACF,KAAO,CAGL,IAAME,EAAaV,EAA4B,aAAa,EAE5D,GAAI,CAACU,EAAW,CACdR,EAAO,KAAK,0CAA2C,CAAE,UAAAQ,CAAU,CAAC,EACpE,MACF,CAGA,IAAMC,EAAQC,EAAYF,CAAS,EAG7B,CAAC,CAAEH,CAAU,EAAIF,EAGnB,SAAUE,IAEZA,EAAW,KAAK,OAASG,GAAA,YAAAA,EAAW,UAGtCR,EAAO,QAAQS,CAAK,EAAE,MAAM,kCAAmC,CAC7D,WAAAJ,EACA,QAAAF,CACF,CAAC,EAEDL,EAAe,KAAK,CAClB,OAAQ,MACR,QAAS,CACP,QAAAK,EACA,cAAeC,GAAiB,CAAC,CACnC,CACF,CAAC,CACH,CACF,EACA,iBAAkB,CAACO,EAAOC,IAAa,CACrCd,EAAe,GAAG,CAChB,IAAK,CAACK,EAA0BU,IAAqB,CACnD,GAAI,CACF,GAAI,CAACA,EACHb,EAAO,MAAM,wBAAyB,CACpC,QAAAG,EACA,MAAAQ,CACF,CAAC,MACI,CAEL,IAAMF,EAAQC,EAAYG,CAAI,EAC9Bb,EAAO,QAAQS,CAAK,EAAE,MAAM,wBAAyB,CACnD,QAAAN,EACA,MAAAQ,CACF,CAAC,CACH,CAEA,GAAM,CAAE,QAAAG,CAAQ,EAAIX,EACd,CAAE,QAASY,EAAiB,cAAAX,EAAgB,CAAC,CAAE,EAAIU,EACnDE,EAAW,IAAI,aAAa,UAAW,CAC3C,KAAMD,EACN,MACGX,EAAc,OACZa,GAAeA,aAAa,WAC/B,GAAuB,CAAC,CAC5B,CAAC,EACDL,EAASI,CAAQ,CACnB,OAASE,EAAG,CACVlB,EAAO,MAAM,uCAAwCkB,CAAC,CACxD,CACF,CACF,CAAC,CACH,EACA,oBAAqB,IAAM,CAE3B,EAEA,QAAS,CACP,gBAAAnB,EACA,UAAYA,EAER,OADCD,EAA4B,aAAa,CAEhD,CACF,EAEA,OAAOqB,EAAejB,EAAiBR,EAAcC,EAASE,CAAQ,CACxE,CAIA,SAASU,GAAqBO,EAA0B,CACtD,GAAI,WAAYA,EAAS,OAAOA,EAAQ,OAAO,OAC/C,GAAI,UAAWA,EAAS,OAAOA,EAAQ,MAAM,OAC7C,GAAI,SAAUA,EAAS,OAAOA,EAAQ,KAAK,OAC3C,GAAI,YAAaA,EAAS,OAAOA,EAAQ,QAAQ,MAEnD,CLvHO,IAAMM,EAAN,MAAMA,CAAiC,CAuB5C,YAAoBC,EAAiBC,EAAwB,CAAzC,YAAAD,EArBpB,KAAQ,UAAwD,IAAI,IAIpE,KAAQ,qBAQJ,CAAC,EACL,KAAQ,uBAEJ,CAAC,EACL,KAAQ,cAAgB,SACxB,KAAQ,UAAS,WAAO,QAAS,CAAE,MAAO,EAAM,CAAC,EAM3CC,GAAA,MAAAA,EAAS,QACXC,EAAa,SAAS,EAAI,EAC1BC,EAAO,SAAS,EAAI,GAEtB,KAAK,eAAgBF,GAAA,YAAAA,EAAS,gBAAiB,KAAK,cAGpD,KAAK,OAASE,EAAO,WAAW,MAAM,EACtC,KAAK,OAAO,IAAI,oCAAoC,EAGpD,KAAK,qBAAuB,KAAK,0BAA0B,EAC3D,KAAK,oBAAsB,KAAK,aAC9B,KAAK,yBAAyB,EAChC,KAAK,QAAQ,EAGb,KAAK,OAAO,IAAI,qDAAqD,EACrE,KAAK,OAAO,GAAG,CACb,SAAU,CAACC,EAASC,IAAS,CAC3B,GAAI,CAACA,EAAM,CACT,KAAK,OAAO,KAAK,2CAA2C,EAC5D,MACF,CAEA,IAAMC,EAAWC,EAAYF,CAAI,EACjC,KAAK,OAAO,QAAQC,CAAQ,EAAE,IAAI,iBAAkBF,CAAO,EAC3D,KAAK,IAAIA,EAAQ,QAAQ,MAAOC,EAAK,EAAE,CACzC,CACF,CAAC,EAGD,IAAMG,EAAoB,IAAI,IAG9B,KAAK,OAAO,cAAeH,GAAoB,CAC7C,GAAI,CAACA,EAAM,CACT,KAAK,OAAO,MAAM,kCAAmC,CAAE,KAAAA,CAAK,CAAC,EAC7D,MACF,CAEA,IAAMC,EAAWC,EAAYF,CAAI,EAUjC,GATA,KAAK,OAAO,QAAQC,CAAQ,EAAE,IAAI,oCAAqC,CACrE,GAAID,EAAK,GACT,QAASA,EAAK,SAAS,QACvB,MAAOA,EAAK,SAAS,MACrB,QAASA,EAAK,SAAS,QACvB,mBAAoBG,EAAkB,IAAIH,EAAK,EAAE,CACnD,CAAC,EAGGG,EAAkB,IAAIH,EAAK,EAAE,EAAG,CAClC,KAAK,OACF,QAAQC,CAAQ,EAChB,IAAI,gDAAiDD,EAAK,EAAE,EAC/D,MACF,CAGAG,EAAkB,IAAIH,EAAK,EAAE,EAE7B,KAAK,OACF,QAAQC,CAAQ,EAChB,IAAI,gDAAiD,CAAE,KAAAD,CAAK,CAAC,EAChE,IAAMI,EAAY,KAAK,IAAIJ,EAAK,EAAE,EAClC,KAAK,OAAO,KACV,CACE,OAAQ,eACR,QAAS,CAAE,MAAOI,EAAW,KAAAJ,CAAK,CACpC,EACAA,EAAK,QACP,EAEA,KAAK,oBAAoBA,EAAK,GAAIA,CAAI,CACxC,CAAC,EAGD,KAAK,OAAO,UAAWA,GAAoB,CACzC,GAAI,CAACA,EAAM,CACT,KAAK,OAAO,MAAM,qCAAsC,CAAE,KAAAA,CAAK,CAAC,EAChE,MACF,CACA,IAAMC,EAAWC,EAAYF,CAAI,EACjC,KAAK,OAAO,QAAQC,CAAQ,EAAE,IAAI,kBAAmB,CAAE,KAAAD,CAAK,CAAC,EAC7D,KAAK,YAAYA,EAAK,GAAIC,CAAQ,EAClC,KAAK,OAAO,aAAcD,GAAoB,CAC5C,KAAK,OACF,QAAQE,EAAYF,CAAI,CAAC,EACzB,IACC,iEACA,CAAE,KAAAA,CAAK,CACT,EACF,KAAK,eAAeA,EAAK,EAAE,CAC7B,CAAC,CACH,CAAC,EAGD,IAAMK,EAAU,KAAK,eAAeV,CAAM,EAC1C,KAAK,YAAcW,EACjB,KAAK,IAAI,EACTD,EACA,KAAK,OACJE,GAA6C,KAAK,IAAIA,CAAQ,CACjE,CACF,CAEA,OAAc,YACZZ,EACAC,EACgB,CAChB,OAAKF,EAAM,SAEAE,GAAA,MAAAA,EAAS,OACHE,EAAO,WAAW,MAAM,EAChC,IAAI,mDAAmD,EAH9DJ,EAAM,SAAW,IAAIA,EAAMC,EAAQC,CAAO,EAKrCF,EAAM,QACf,CAOA,MAAc,YAAYc,EAAaP,EAAiC,CACtE,GAAK,KAAK,UAAU,IAAIO,CAAG,EAOzB,KAAK,OACF,QAAQP,CAAQ,EAChB,IAAI,4DAA4D,MATvC,CAC5B,KAAK,OAAO,QAAQA,CAAQ,EAAE,IAAI,gCAAgC,EAClE,IAAMQ,EAAuB,CAC3B,GAAG,KAAK,oBACV,EACA,KAAK,UAAU,IAAID,EAAKC,CAAoB,CAC9C,CAKF,CAEA,MAAc,eAAeD,EAA4B,CACnD,KAAK,UAAU,IAAIA,CAAG,GACxB,KAAK,OAAO,QAAQA,CAAG,EAAE,IAAI,2BAA2B,EACxD,KAAK,UAAU,OAAOA,CAAG,GAEzB,KAAK,OACF,QAAQA,CAAG,EACX,IAAI,iDAAiD,CAE5D,CAGA,MAAa,gBACXE,EACe,CACf,KAAK,OAAO,IAAI,qCAAsCA,CAAK,EAC3D,IAAMC,EAAS,CAAE,GAAG,KAAK,aAAc,GAAGD,CAAM,EAC3CE,EAAU,KAAK,aAAcD,CAAM,EAQtC,KAAK,OAAO,IAAI,sDAAsD,GAPtE,KAAK,OAAO,IACV,+GACF,EACA,KAAK,aAAeA,EACpB,MAAM,KAAK,QAAQD,CAAK,EACxB,KAAK,OAAOA,CAAuC,EAIvD,CAGA,MAAa,iBACXF,EACAE,EACe,CACf,KAAK,OACF,QAAQF,CAAG,EACX,IAAI,4CAA6CE,CAAK,EACzD,IAAMG,EAAe,KAAK,UAAU,IAAIL,CAAG,GAAK,KAAK,qBAC/CG,EAAS,CAAE,GAAGE,EAAc,GAAGH,CAAM,EACtCE,EAAUC,EAAcF,CAAM,EAOjC,KAAK,OACF,QAAQH,CAAG,EACX,IAAI,0DAA0D,GARjE,KAAK,OACF,QAAQA,CAAG,EACX,IAAI,6DAA6D,EACpE,KAAK,UAAU,IAAIA,EAAKG,CAAM,EAC9B,KAAK,OAAOD,EAAyCF,CAAG,EAM5D,CAIA,MAAc,QACZE,EACe,CACf,KAAK,OAAO,IAAI,kBAAkB,EAClC,IAAII,EAAe,GACnB,QAAWN,KAAOE,GAAS,KAAK,aAAc,CAE5C,IAAMK,EADO,KAAK,OAAOP,CAAG,EACH,SAAW,OAC9BQ,EAAQN,EACVA,EAAMF,CAAyC,EAC/C,KAAK,aAAaA,CAAG,EACzB,OAAQO,EAAa,CACnB,IAAK,UACH,MAAM,EAAAE,QAAQ,QAAQ,QAAQ,IAAI,CAChC,CAAC,KAAK,cAAiBT,CAAc,EAAGQ,CAC1C,CAAC,EACDF,EAAe,GACf,MACF,IAAK,QACH,MAAM,EAAAG,QAAQ,QAAQ,MAAM,IAAI,CAC9B,CAAC,KAAK,cAAiBT,CAAc,EAAGQ,CAC1C,CAAC,EACDF,EAAe,GACf,MACF,QACE,KACJ,CACF,CACIA,EACF,KAAK,OAAO,IAAI,qBAAqB,EAErC,KAAK,OAAO,IAAI,oBAAoB,CAExC,CAEA,MAAa,OAAuB,CAClC,KAAK,OAAO,IAAI,gBAAgB,EAChC,KAAK,aAAe,KAAK,oBACzB,KAAK,UAAU,QAAQ,CAACI,EAAGV,IAAQ,CACjC,KAAK,UAAU,IAAIA,EAAK,KAAK,oBAAoB,CACnD,CAAC,EACD,MAAM,KAAK,QAAQ,EACnB,KAAK,OAAO,CAAC,CAAC,CAChB,CAEO,UACLW,EAOM,CACN,KAAK,OAAO,IAAI,sBAAsB,EACtC,KAAK,qBAAqB,KAAKA,CAAQ,CACzC,CAIQ,OAAOC,EAAyCZ,EAAoB,CAC1E,IAAMa,EAAQb,EAAM,KAAK,OAAO,aAAaA,CAAG,EAAI,OAC9CE,EAAQF,EAAM,KAAK,IAAIA,CAAG,EAAI,KAAK,IAAI,EAEzC,KAAK,qBAAqB,OAAS,IACrC,KAAK,OAAO,IAAI,4CAA4C,EAC5D,KAAK,qBAAqB,QAASW,GAAa,CAC9CA,EAAST,EAAOU,EAASC,GAAA,YAAAA,EAAO,IAAI,CACtC,CAAC,GAGCb,IAAOa,GAAA,MAAAA,EAAO,KAAK,WACrB,KAAK,OAAO,QAAQb,CAAG,EAAE,IAAI,4BAA4B,EACzD,KAAK,OAAO,KACV,CAAE,OAAQ,cAAe,QAAS,CAAE,MAAOY,CAAQ,CAAE,EACrDC,EAAM,KAAK,QACb,IAEA,KAAK,OAAO,IAAI,oBAAoB,EAEpC,KAAK,UAAU,QAAQ,CAACH,EAAGV,IAAQ,CACjC,KAAK,OAAO,KACV,CAAE,OAAQ,cAAe,QAAS,CAAE,MAAOY,CAAQ,CAAE,EACrDZ,CACF,CACF,CAAC,EAEL,CAMO,IACLA,EACsD,CACtD,OAAKA,EAGE,CAAE,GAAG,KAAK,aAAc,GAAG,KAAK,UAAU,IAAIA,CAAG,CAAE,EAFjD,CAAE,GAAG,KAAK,YAAuD,CAG5E,CAGO,aAAac,EAA0C,CAC5D,IAAMD,EAAQ,KAAK,OAAO,mBAAmBC,CAAQ,EACrD,GAAI,CAACD,EACH,YAAK,OAAO,IAAI,qCAAsC,CAAE,SAAAC,CAAS,CAAC,EAC3D,KAET,OAAW,CAACd,EAAKe,CAAQ,IAAK,KAAK,UACjC,GAAIf,IAAQa,EAAM,KAAK,GACrB,YAAK,OAAO,IAAI,0BAA2Bb,CAAG,EACvCA,EAGX,YAAK,OAAO,IAAI,oDAAqD,CACnE,SAAAc,CACF,CAAC,EACM,IACT,CAGO,YAAYE,EAA0C,CAC3D,OAAO,KAAK,OAAO,YAAYA,CAAK,CACtC,CAOA,MAAa,IACXd,EACAF,EACe,CACf,IAAMe,EAAW,CAAC,EACZE,EAAS,CAAC,EAEhB,QAAWC,KAAWhB,EAAO,CAC3B,IAAMiB,EAAO,KAAK,OAAOD,CAAwB,EACjD,GAAIE,GAAaD,CAAI,GACnB,GAAIA,EAAK,YAAc,WAAY,CACjC,IAAME,EACJH,EACII,EAAgBpB,EACtBa,EAASM,CAAe,EAAIC,EAAcD,CAAe,CAC3D,SAAW,CAACF,EAAK,WAAaA,EAAK,YAAcI,EAAU,QAAS,CAClE,IAAMC,EAAiBN,EACjBO,EAAevB,EACrBe,EAAOO,CAAc,EAAIC,EAAaD,CAAc,CACtD,EAEJ,CAEIxB,GAAO,OAAO,KAAKe,CAAQ,EAAE,OAAS,IACxC,KAAK,OAAO,QAAQf,CAAG,EAAE,IAAI,0BAA2Be,CAAQ,EAChE,KAAK,iBAAiBf,EAAKe,CAAQ,GAEjC,OAAO,KAAKE,CAAM,EAAE,OAAS,IAC/B,KAAK,OAAO,IAAI,yBAA0BA,CAAM,EAChD,KAAK,gBAAgBA,CAAM,EAE/B,CAEA,MAAc,SAAyB,CACrC,KAAK,OAAO,IAAI,+BAA+B,EAC/C,IAAMS,EAAQ,MAAM,EAAAjB,QAAQ,QAAQ,MAAM,IAAI,IAAI,EAC5CkB,EAAU,MAAM,EAAAlB,QAAQ,QAAQ,QAAQ,IAAI,IAAI,EAChDmB,EAAW,CAAE,GAAGF,EAAO,GAAGC,CAAQ,EAClCxB,EAAgD,CAAC,EACnD0B,EAAW,GACf,QAAWC,KAAeF,EAAU,CAClC,IAAM5B,EAAM,KAAK,aAAa8B,CAAW,EACzC,GAAI,KAAK,OAAO,eAAe9B,CAAG,EAAG,CACnC,IAAMQ,EAAQoB,EAAS5B,CAAG,EAC1BG,EAAOH,CAAyC,EAAIQ,EACpDqB,EAAW,EACb,CACF,CACIA,EACF,KAAK,OAAO,IAAI,sBAAsB,EAEtC,KAAK,OAAO,IAAI,4BAA4B,EAE9C,KAAK,aAAe,CAAE,GAAG,KAAK,oBAAqB,GAAG1B,CAAO,CAC/D,CAEQ,aAAaH,EAAqB,CACxC,OAAIA,EAAI,WAAW,KAAK,aAAa,EAC5BA,EAAI,QAAQ,KAAK,cAAe,EAAE,EAEpCA,CACT,CAEQ,2BAA2D,CACjE,IAAMsB,EAAqB,CAAC,EAC5B,cAAO,KAAK,KAAK,MAAM,EAAE,QAAStB,GAAQ,CACxC,IAAMmB,EAAO,KAAK,OAAOnB,CAAG,EACxB+B,EAAYZ,CAAI,GAAKA,EAAK,YAAc,aAC1CG,EAActB,CAAG,EAAImB,EAAK,QAE9B,CAAC,EACMG,CACT,CAEQ,0BAAyD,CAC/D,IAAMG,EAAoB,CAAC,EAC3B,cAAO,KAAK,KAAK,MAAM,EAAE,QAASzB,GAAQ,CACxC,IAAMmB,EAAO,KAAK,OAAOnB,CAAG,EAE1B+B,EAAYZ,CAAI,IACf,CAACA,EAAK,WAAaA,EAAK,YAAcI,EAAU,WAEjDE,EAAazB,CAAG,EAAImB,EAAK,QAE7B,CAAC,EACMM,CACT,CAEO,yBACLd,EACY,CACZ,YAAK,OAAO,IAAI,sCAAsC,EACtD,KAAK,uBAAuB,KAAKA,CAAQ,EAEzC,KAAK,UAAU,QAAQ,CAACD,EAAGsB,IAAe,CACxC,IAAMnB,EAAQ,KAAK,OAAO,aAAamB,CAAU,EAC7CnB,GAAA,MAAAA,EAAO,MACTF,EAASqB,EAAYnB,EAAM,IAAI,CAEnC,CAAC,EAEM,IAAM,CACX,KAAK,OAAO,IAAI,0CAA0C,EAC1D,IAAMoB,EAAQ,KAAK,uBAAuB,QAAQtB,CAAQ,EACtDsB,IAAU,IACZ,KAAK,uBAAuB,OAAOA,EAAO,CAAC,CAE/C,CACF,CAEQ,oBAAoBD,EAAoBxC,EAAuB,CACrE,GAAI,KAAK,uBAAuB,OAAS,EAAG,CAC1C,IAAMC,EAAWC,EAAYF,CAAI,EACjC,KAAK,OAAO,QAAQC,CAAQ,EAAE,IAAI,oCAAoC,EACtE,KAAK,uBAAuB,QAASkB,GAAa,CAChDA,EAASqB,EAAYxC,CAAI,CAC3B,CAAC,CACH,CACF,CAEQ,eACNL,EACqE,CACrE,OAAO,OAAO,QAAQA,CAAM,EACzB,OAAO,CAAC,CAACuB,EAAGF,CAAK,IAAM0B,EAAa1B,CAAK,CAAC,EAC1C,OAEC,CAAC2B,EAAK,CAACnC,EAAKQ,CAAK,IAAM,CACvB,IAAM4B,EAAS5B,EAKf,MAAO,CACL,GAAG2B,EACH,CAACnC,CAAG,EAAGoC,CACT,CACF,EAAG,CAAC,CAAC,CACT,CACF,EAvealD,EACI,SAA8B,KA8KhCmD,EAAA,CADZC,GA9KUpD,EA+KE,+BAkBAmD,EAAA,CADZC,GAhMUpD,EAiME,gCAjMR,IAAMqD,EAANrD,EAygBA,SAASsD,GACdrD,EACAC,EACmB,CACnB,IAAM2B,EAAWwB,EAAM,YAAYpD,EAAQC,CAAO,EAElD,MAAO,CACL,IAAK2B,EAAS,IAAI,KAAKA,CAAQ,EAC/B,IAAKA,EAAS,IAAI,KAAKA,CAAQ,EAC/B,UAAWA,EAAS,UAAU,KAAKA,CAAQ,EAC3C,gBAAiBA,EAAS,yBAAyB,KAAKA,CAAQ,EAChE,aAAcA,EAAS,aAAa,KAAKA,CAAQ,EACjD,YAAaA,EAAS,YAAY,KAAKA,CAAQ,EAC/C,MAAOA,EAAS,MAAM,KAAKA,CAAQ,CACrC,CACF,CAEA,SAASK,GAAaD,EAAoC,CACxD,OAAOA,GAAQ,OAAOA,GAAS,UAAY,YAAaA,CAC1D,CSriBA,IAAAsB,GAAoD,yBAKpD,IAAIC,EAAqC,CAAE,UAAW,EAAM,EACxDC,EAAyB,KAEtB,SAASC,EACdC,EACAC,EACwB,CACxB,IAAMC,GAAQD,GAAA,YAAAA,EAAS,QAAS,GAC1BE,EAAUF,GAAA,YAAAA,EAAS,QAGrBC,GACFE,EAAO,SAAS,EAAI,EAEtB,IAAMC,EAASD,EAAO,WAAW,OAAO,EAEpCE,EACAC,EAAS,QACPC,EAAiB,IAAI,IAK3B,GAHAH,EAAO,IACL,4BAA8BF,EAAU,kBAAkBA,CAAO,GAAK,GACxE,EACIL,EACF,OAAAO,EAAO,IAAI,uCAAuC,EAE9CR,EAAiB,YACnBQ,EAAO,IAAI,mCAAmC,EAC9C,WAAW,IAAM,CACfG,EAAe,QAASC,GAAaA,EAASZ,CAAgB,CAAC,CACjE,EAAG,CAAC,GAECC,EAGTO,EAAO,IAAI,0CAA0C,EACrD,IAAMK,KAAS,GAAAC,SAAc,CAC3B,UAAW,QACX,MAAO,EACT,CAAC,EAEDN,EAAO,IAAI,2BAA2B,EAGtC,IAAMO,EAAU,OAAO,QAAQZ,CAAM,EAClC,OAAO,CAAC,CAACa,EAAGC,CAAK,IAAMC,EAAaD,CAAK,CAAC,EAC1C,OAEC,CAACE,EAAK,CAACC,EAAKH,CAAK,IAAM,CACvB,IAAMI,EAASJ,EAKf,MAAO,CACL,GAAGE,EACH,CAACC,CAAG,EAAG,CACL,KAAM,SACN,QAASC,EAAO,QAChB,SAAUA,EAAO,QACnB,CACF,CACF,EAAG,CAAC,CAAC,EAEDC,EAAcC,EAClBC,GAAgBrB,CAAM,EACtBY,EACAF,CACF,EAEIY,EAAuB,GAE3BZ,EAAO,GAAG,CACR,aAAea,GAAY,CAMzB,GALAlB,EAAO,IAAI,wBAAyB,CAClC,gBAAiBiB,EACjB,QAASC,EAAQ,OACnB,CAAC,EAEGD,EAAsB,CACxBjB,EAAO,IAAI,yCAAyC,EACpD,MACF,CAEAiB,EAAuB,GAEvBE,EAASD,EAAQ,QAAQ,MACzBjB,EAAUiB,EAAQ,QAAQ,KAC1BhB,EAASkB,EAAYnB,CAAO,EAC5BT,EAAmB,CAAE,UAAW,GAAM,MAAOS,CAAQ,EAGrDD,EAAO,OAAOE,CAAM,EACpBF,EAAO,IACL,8BAA8BqB,EAAU,IAAI,sBAC5C,CACE,QAAAH,CACF,CACF,EACAf,EAAe,QAASC,GAAa,CACnCJ,EAAO,IAAI,2BAA2B,EACtCI,EAASZ,CAAgB,CAC3B,CAAC,EACD6B,EAAU,QAASC,GAAa,CAC9BA,EAAS,SAASH,CAAM,CAC1B,CAAC,CACH,EACA,YAAcD,GAAY,CACxBK,EAAUL,EAAQ,QAAQ,MAC1BC,EAAS,CAAE,GAAGA,EAAQ,GAAGI,CAAQ,EACjCvB,EAAO,IAAI,iBAAkB,CAAE,QAAAkB,EAAS,QAAAK,EAAS,OAAAJ,CAAO,CAAC,EACpDI,GAELF,EAAU,QAASC,GAAa,EAC1BA,EAAS,OAAS,QAGDA,EAAS,KAAK,KAAMV,GAAQA,KAAOW,CAAQ,IAE5DD,EAAS,SAASC,CAAQ,CAGhC,CAAC,CACH,CACF,CAAC,EACDvB,EAAO,IAAI,kDAAkD,EAC7D,IAAImB,EAASH,GAAgBrB,CAAM,EAC/B4B,EAAiD,KAC/CF,EAAY,IAAI,IAEtBrB,EAAO,IAAI,qCAAqC,EAEhD,IAAMwB,EAAM,IAAML,EACZM,EAAOC,GAA6C,CACxD1B,EAAO,IAAI,6BAA8B0B,CAAQ,EACjDrB,EAAO,KAAK,CAAE,OAAQ,WAAY,QAAS,CAAE,MAAOqB,CAAS,CAAE,CAAC,CAClE,EAEMC,EAAY,CAChBvB,EACAwB,IACiB,CACjB,IAAMN,EAAW,CAAE,KAAAM,EAAM,SAAAxB,CAAS,EAClC,OAAAiB,EAAU,IAAIC,CAAQ,EACf,IAAM,CACXD,EAAU,OAAOC,CAAQ,CAC3B,CACF,EAsEA,OAAA7B,EAViB,CACf,SA1DAmB,GACG,CACH,IAAMiB,EAAW,IACDL,EAAI,EAAEZ,CAAG,EAMnBkB,EACJrB,GACGgB,EAAI,CAAE,CAACb,CAAG,EAAGH,CAAM,CAAmC,EAErDsB,EACJ3B,GACG,CACH,IAAI4B,EAAgBH,EAAS,EAE7B,OAAOF,EACJJ,IAAY,CACX,GAAIX,KAAOW,GAAS,CAClB,IAAMU,EAAeJ,EAAS,EACxBK,GAAYV,EAAI,EACtBpB,EAAS,CACP,QAAS6B,EACT,SAAUD,EACV,MAAOE,EACT,CAAkC,EAClCF,EAAgBC,CAClB,CACF,EACA,CAACrB,CAAG,CACN,CACF,EAEA,MAAO,CAACiB,EAAS,EAAGC,EAAUC,CAAkB,CAClD,EAuBE,IAAAP,EACA,IAAAC,EACA,UAAAE,EACA,aAZmB,IAAM1B,EAazB,QAzBeG,IACfJ,EAAO,IAAI,wBAAwB,EACnCG,EAAe,IAAIC,CAAQ,EACvBZ,EAAiB,YACnBQ,EAAO,IAAI,0BAA0B,EACrC,WAAW,IAAM,CACfI,EAASZ,CAAgB,CAC3B,EAAG,CAAC,GAEC,IAAMW,EAAe,OAAOC,CAAQ,GAiB3C,WAZiB,MAAO+B,KAAiBC,KACzCpC,EAAO,IAAI,iBAAkBmC,EAAMC,CAAI,EAC/BtB,EAAoBqB,CAAI,EAAE,GAAGC,CAAI,EAW3C,EAIO3C,CACT,CAEO,SAAS4C,IAAqB,CACnC,OAAO5C,IAAkB,IAC3B,CAEA,SAASuB,GACPrB,EACuB,CACvB,IAAM2C,EAAa,CAAC,EACpB,cAAO,KAAK3C,CAAM,EAAE,QAASiB,GAAQ,CACnC,IAAM2B,EAAO5C,EAAOiB,CAAG,EACnB4B,EAAYD,CAAI,IAClBD,EAAM1B,CAAG,EAAI2B,EAAK,QAEtB,CAAC,EACMD,CACT,CC/PA,IAAAG,EAAkE,iBAI3D,SAASC,GAEdC,EAAiB,CACjB,OAAO,SAAuBC,EAAkB,CAC9C,GAAM,CAAE,SAAAC,EAAU,IAAAC,EAAK,IAAAC,EAAK,UAAAC,EAAW,WAAAC,CAAW,KAAI,WAAQ,IAC3CC,EAAQP,CAAM,EAE9B,CAACC,CAAO,CAAC,EAENO,KAAe,eACqBC,GAAW,CACjD,GAAM,CAACC,EAAOC,CAAQ,KAAI,YACxBR,EAAI,EAAEM,CAAG,CACX,EACMG,KAAW,UAAOF,CAAK,KAE7B,aAAU,IAAM,CACdE,EAAS,QAAUF,CACrB,EAAG,CAACA,CAAK,CAAC,KAEV,aAAU,KACRC,EAASR,EAAI,EAAEM,CAAG,CAAC,EACCJ,EACjBQ,GAAkC,CAC7BJ,KAAOI,GACTF,EAASE,EAAQJ,CAAG,CAA6B,CAErD,EACA,CAACA,CAAG,CACN,GAEC,CAACA,CAAG,CAAC,EAER,IAAMK,KAAc,eACjBC,GAAuC,CACtCX,EAAI,CAAE,CAACK,CAAG,EAAGM,CAAS,CAAmC,CAC3D,EACA,CAACN,CAAG,CACN,EAEA,MAAO,CAACC,EAAOI,CAAW,CAC5B,EACA,CAACX,EAAKC,EAAKC,CAAS,CACtB,EAEMW,KAAW,eAAY,IAAMb,EAAI,EAAG,CAACA,CAAG,CAAC,EAEzCc,KAAW,eACdC,GAA6C,CAC5Cd,EAAIc,CAAQ,CACd,EACA,CAACd,CAAG,CACN,EAEA,MAAO,CACL,aAAAI,EACA,SAAAQ,EACA,SAAAC,EACA,SAAAf,EACA,WAAAI,CACF,CACF,CACF",
4
+ "sourcesContent": ["export { create, Crann } from \"./crann\";\nexport { connect, connected } from \"./crannAgent\";\nexport { createCrannStateHook } from \"./hooks/useCrannState\";\nexport {\n CrannAgent,\n StateUpdate,\n State,\n Partition,\n Persistence,\n ConfigItem,\n DerivedState,\n} from \"./model/crann.model\";\n", "import browser from \"webextension-polyfill\";\nimport {\n DerivedInstanceState,\n DerivedServiceState,\n ConfigItem,\n DerivedState,\n Partition,\n CrannOptions,\n ActionDefinition,\n AnyConfig,\n isStateItem,\n isActionItem,\n} from \"./model/crann.model\";\nimport { AgentInfo, source, Agent } from \"porter-source\";\nimport { deepEqual } from \"./utils/deepEqual\";\nimport { BrowserLocation } from \"porter-source\";\nimport { trackStateChange } from \"./utils/tracking\";\nimport { DebugManager } from \"./utils/debug\";\nimport { createCrannRPCAdapter } from \"./rpc/adapter\";\nimport { Logger } from \"./utils/logger\";\nimport { getAgentTag } from \"./utils/agent\";\n\nexport class Crann<TConfig extends AnyConfig> {\n private static instance: Crann<any> | null = null;\n private instances: Map<string, DerivedInstanceState<TConfig>> = new Map();\n private defaultServiceState: DerivedServiceState<TConfig>;\n private defaultInstanceState: DerivedInstanceState<TConfig>;\n private serviceState: DerivedServiceState<TConfig>;\n private stateChangeListeners: Array<\n (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedServiceState<TConfig> & DerivedInstanceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n > = [];\n private instanceReadyListeners: Array<\n (instanceId: string, agent: AgentInfo) => void\n > = [];\n private storagePrefix = \"crann_\";\n private porter = source(\"crann\", { debug: false });\n private rpcEndpoint: ReturnType<typeof createCrannRPCAdapter>;\n private logger: Logger;\n\n constructor(private config: TConfig, options?: CrannOptions) {\n // Set the debug flag globally\n if (options?.debug) {\n DebugManager.setDebug(true);\n Logger.setDebug(true);\n }\n this.storagePrefix = options?.storagePrefix ?? this.storagePrefix;\n\n // Set up the core logger\n this.logger = Logger.forContext(\"Core\");\n this.logger.log(\"Constructing Crann with new logger\");\n\n // Hydrate the initial state from the config defaults and from storage\n this.defaultInstanceState = this.initializeInstanceDefault();\n this.defaultServiceState = this.serviceState =\n this.initializeServiceDefault();\n this.hydrate();\n\n // Set up the message handlers\n this.logger.log(\"Crann constructed, setting initial message handlers\");\n this.porter.on({\n setState: (message, info) => {\n if (!info) {\n this.logger.warn(\"setState message heard from unknown agent\");\n return;\n }\n\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Setting state:\", message);\n this.set(message.payload.state, info.id);\n },\n });\n\n // Track which agents we've already sent initialState to\n const agentsInitialized = new Set<string>();\n\n // Once the agents are connected and have set up their listeners, send them the initial state\n this.porter.onMessagesSet((info: AgentInfo) => {\n if (!info) {\n this.logger.error(\"Messages set but no agent info.\", { info });\n return;\n }\n\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"onMessagesSet received for agent:\", {\n id: info.id,\n context: info.location.context,\n tabId: info.location.tabId,\n frameId: info.location.frameId,\n alreadyInitialized: agentsInitialized.has(info.id),\n });\n\n // Skip sending initialState if we've already sent it to this agent\n if (agentsInitialized.has(info.id)) {\n this.logger\n .withTag(agentTag)\n .log(\"Already sent initialState to agent, skipping:\", info.id);\n return;\n }\n\n // Add the agent to the set of agents we've already sent initialState to\n agentsInitialized.add(info.id);\n\n this.logger\n .withTag(agentTag)\n .log(\"Messages set received. Sending initial state.\", { info });\n const fullState = this.get(info.id);\n this.porter.post(\n {\n action: \"initialState\",\n payload: { state: fullState, info },\n },\n info.location\n );\n\n this.notifyInstanceReady(info.id, info);\n });\n\n // Handle agent connection and disconnection\n this.porter.onConnect((info: AgentInfo) => {\n if (!info) {\n this.logger.error(\"Agent connected but no agent info.\", { info });\n return;\n }\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Agent connected\", { info });\n this.addInstance(info.id, agentTag);\n this.porter.onDisconnect((info: AgentInfo) => {\n this.logger\n .withTag(getAgentTag(info))\n .log(\n \"Agent disconnect heard. Connection type, context and location:\",\n { info }\n );\n this.removeInstance(info.id);\n });\n });\n\n // Initialize RPC with actions\n const actions = this.extractActions(config);\n this.rpcEndpoint = createCrannRPCAdapter(\n this.get(),\n actions,\n this.porter,\n (newState: Partial<DerivedState<TConfig>>) => this.set(newState)\n );\n }\n\n public static getInstance<TConfig extends AnyConfig>(\n config: TConfig,\n options?: CrannOptions\n ): Crann<TConfig> {\n if (!Crann.instance) {\n Crann.instance = new Crann(config, options);\n } else if (options?.debug) {\n const logger = Logger.forContext(\"Core\");\n logger.log(\"Instance requested and already existed, returning\");\n }\n return Crann.instance;\n }\n\n /**\n * Add an instance to the Crann instance.\n * @param key The key of the instance to add.\n * @param agentTag The tag of the agent that is adding the instance, for logging.\n */\n private async addInstance(key: string, agentTag: string): Promise<void> {\n if (!this.instances.has(key)) {\n this.logger.withTag(agentTag).log(\"Adding instance from agent key\");\n const initialInstanceState = {\n ...this.defaultInstanceState,\n } as DerivedInstanceState<TConfig>;\n this.instances.set(key, initialInstanceState);\n } else {\n this.logger\n .withTag(agentTag)\n .log(\"Instance was already registered, ignoring request from key\");\n }\n }\n\n private async removeInstance(key: string): Promise<void> {\n if (this.instances.has(key)) {\n this.logger.withTag(key).log(\"Remove instance requested\");\n this.instances.delete(key);\n } else {\n this.logger\n .withTag(key)\n .log(\"Remove instance requested but it did not exist!\");\n }\n }\n\n @trackStateChange\n public async setServiceState(\n state: Partial<DerivedServiceState<TConfig>>\n ): Promise<void> {\n this.logger.log(\"Request to set service state with:\", state);\n const update = { ...this.serviceState, ...state };\n if (!deepEqual(this.serviceState, update)) {\n this.logger.log(\n \"Confirmed new state was different than existing so proceeding to persist then notify all connected instances.\"\n );\n this.serviceState = update;\n await this.persist(state);\n this.notify(state as Partial<DerivedState<TConfig>>);\n } else {\n this.logger.log(\"New state seems to be the same as existing, skipping\");\n }\n }\n\n @trackStateChange\n public async setInstanceState(\n key: string,\n state: Partial<DerivedInstanceState<TConfig>>\n ): Promise<void> {\n this.logger\n .withTag(key)\n .log(\"Request to update instance state, update:\", state);\n const currentState = this.instances.get(key) || this.defaultInstanceState;\n const update = { ...currentState, ...state };\n if (!deepEqual(currentState, update)) {\n this.logger\n .withTag(key)\n .log(\"Instance state update is different, updating and notifying.\");\n this.instances.set(key, update);\n this.notify(state as Partial<DerivedState<TConfig>>, key);\n } else {\n this.logger\n .withTag(key)\n .log(\"Instance state update is not different, skipping update.\");\n }\n }\n\n // If we pass in specific state to persist, it only persists that state.\n // Otherwise persists all of the worker state.\n private async persist(\n state?: Partial<DerivedServiceState<TConfig>>\n ): Promise<void> {\n this.logger.log(\"Persisting state\");\n let wasPersisted = false;\n for (const key in state || this.serviceState) {\n const item = this.config[key] as ConfigItem<any>;\n const persistence = item.persist || \"none\";\n const value = state\n ? state[key as keyof DerivedServiceState<TConfig>]\n : this.serviceState[key];\n switch (persistence) {\n case \"session\":\n await browser.storage.session.set({\n [this.storagePrefix + (key as string)]: value,\n });\n wasPersisted = true;\n break;\n case \"local\":\n await browser.storage.local.set({\n [this.storagePrefix + (key as string)]: value,\n });\n wasPersisted = true;\n break;\n default:\n break;\n }\n }\n if (wasPersisted) {\n this.logger.log(\"State was persisted\");\n } else {\n this.logger.log(\"Nothing to persist\");\n }\n }\n\n public async clear(): Promise<void> {\n this.logger.log(\"Clearing state\");\n this.serviceState = this.defaultServiceState;\n this.instances.forEach((_, key) => {\n this.instances.set(key, this.defaultInstanceState);\n });\n await this.persist();\n this.notify({});\n }\n\n public subscribe(\n listener: (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n ): void {\n this.logger.log(\"Subscribing to state\");\n this.stateChangeListeners.push(listener);\n }\n\n // Right now we notify the instance even if the state change came from the instance.\n // This should probably be skipped for instance state, since it already knows.\n private notify(changes: Partial<DerivedState<TConfig>>, key?: string): void {\n const agent = key ? this.porter.getAgentById(key) : undefined;\n const state = key ? this.get(key) : this.get();\n\n if (this.stateChangeListeners.length > 0) {\n this.logger.log(\"Notifying state change listeners in source\");\n this.stateChangeListeners.forEach((listener) => {\n listener(state, changes, agent?.info);\n });\n }\n\n if (key && agent?.info.location) {\n this.logger.withTag(key).log(\"Notifying of state change.\");\n this.porter.post(\n { action: \"stateUpdate\", payload: { state: changes } },\n agent.info.location\n );\n } else {\n this.logger.log(\"Notifying everyone\");\n // for every key of this.instances, post the state update to the corresponding key\n this.instances.forEach((_, key) => {\n this.porter.post(\n { action: \"stateUpdate\", payload: { state: changes } },\n key\n );\n });\n }\n }\n\n public get(): DerivedState<TConfig>;\n public get(\n key: string\n ): DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>;\n public get(\n key?: string\n ): DerivedServiceState<TConfig> | DerivedState<TConfig> {\n if (!key) {\n return { ...this.serviceState, ...({} as DerivedInstanceState<TConfig>) };\n }\n return { ...this.serviceState, ...this.instances.get(key) };\n }\n\n // Todo: Should we return the instance data? What is the point of this.\n public findInstance(location: BrowserLocation): string | null {\n const agent = this.porter.getAgentByLocation(location);\n if (!agent) {\n this.logger.log(\"Could not find agent for location:\", { location });\n return null;\n }\n for (const [key, instance] of this.instances) {\n if (key === agent.info.id) {\n this.logger.log(\"Found instance for key:\", key);\n return key;\n }\n }\n this.logger.log(\"Could not find instance for context and location:\", {\n location,\n });\n return null;\n }\n\n // Convenience re-export of the porter-source queryAgents method.\n public queryAgents(query: Partial<BrowserLocation>): Agent[] {\n return this.porter.queryAgents(query);\n }\n\n public async set(state: Partial<DerivedServiceState<TConfig>>): Promise<void>;\n public async set(\n state: Partial<DerivedInstanceState<TConfig>>,\n key: string\n ): Promise<void>;\n public async set(\n state: Partial<DerivedState<TConfig>>,\n key?: string\n ): Promise<void> {\n const instance = {} as Partial<DerivedInstanceState<TConfig>>;\n const worker = {} as Partial<DerivedServiceState<TConfig>>;\n\n for (const itemKey in state) {\n const item = this.config[itemKey as keyof TConfig];\n if (isConfigItem(item)) {\n if (item.partition === \"instance\") {\n const instanceItemKey =\n itemKey as keyof DerivedInstanceState<TConfig>;\n const instanceState = state as Partial<DerivedInstanceState<TConfig>>;\n instance[instanceItemKey] = instanceState[instanceItemKey];\n } else if (!item.partition || item.partition === Partition.Service) {\n const serviceItemKey = itemKey as keyof DerivedServiceState<TConfig>;\n const serviceState = state as Partial<DerivedServiceState<TConfig>>;\n worker[serviceItemKey] = serviceState[serviceItemKey]!;\n }\n }\n }\n\n if (key && Object.keys(instance).length > 0) {\n this.logger.withTag(key).log(\"Setting instance state:\", instance);\n this.setInstanceState(key, instance);\n }\n if (Object.keys(worker).length > 0) {\n this.logger.log(\"Setting service state:\", worker);\n this.setServiceState(worker);\n }\n }\n\n private async hydrate(): Promise<void> {\n this.logger.log(\"Hydrating state from storage.\");\n const local = await browser.storage.local.get(null);\n const session = await browser.storage.session.get(null);\n const combined = { ...local, ...session };\n const update: Partial<DerivedServiceState<TConfig>> = {}; // Cast update as Partial<DerivedState<TConfig>>\n let hadItems = false;\n for (const prefixedKey in combined) {\n const key = this.removePrefix(prefixedKey);\n if (this.config.hasOwnProperty(key)) {\n const value = combined[key];\n update[key as keyof DerivedServiceState<TConfig>] = value;\n hadItems = true;\n }\n }\n if (hadItems) {\n this.logger.log(\"Hydrated some items.\");\n } else {\n this.logger.log(\"No items found in storage.\");\n }\n this.serviceState = { ...this.defaultServiceState, ...update };\n }\n\n private removePrefix(key: string): string {\n if (key.startsWith(this.storagePrefix)) {\n return key.replace(this.storagePrefix, \"\");\n }\n return key;\n }\n\n private initializeInstanceDefault(): DerivedInstanceState<TConfig> {\n const instanceState: any = {};\n Object.keys(this.config).forEach((key) => {\n const item = this.config[key];\n if (isStateItem(item) && item.partition === \"instance\") {\n instanceState[key] = item.default;\n }\n });\n return instanceState;\n }\n\n private initializeServiceDefault(): DerivedServiceState<TConfig> {\n const serviceState: any = {};\n Object.keys(this.config).forEach((key) => {\n const item = this.config[key];\n if (\n isStateItem(item) &&\n (!item.partition || item.partition === Partition.Service)\n ) {\n serviceState[key] = item.default;\n }\n });\n return serviceState;\n }\n\n public subscribeToInstanceReady(\n listener: (instanceId: string, agent: AgentInfo) => void\n ): () => void {\n this.logger.log(\"Subscribing to instance ready events\");\n this.instanceReadyListeners.push(listener);\n\n this.instances.forEach((_, instanceId) => {\n const agent = this.porter.getAgentById(instanceId);\n if (agent?.info) {\n listener(instanceId, agent.info);\n }\n });\n\n return () => {\n this.logger.log(\"Unsubscribing from instance ready events\");\n const index = this.instanceReadyListeners.indexOf(listener);\n if (index !== -1) {\n this.instanceReadyListeners.splice(index, 1);\n }\n };\n }\n\n private notifyInstanceReady(instanceId: string, info: AgentInfo): void {\n if (this.instanceReadyListeners.length > 0) {\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Notifying instance ready listeners\");\n this.instanceReadyListeners.forEach((listener) => {\n listener(instanceId, info);\n });\n }\n }\n\n private extractActions(\n config: TConfig\n ): Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>> {\n return Object.entries(config)\n .filter(([_, value]) => isActionItem(value))\n .reduce<\n Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>\n >((acc, [key, value]) => {\n const action = value as ActionDefinition<\n DerivedState<TConfig>,\n any[],\n any\n >;\n return {\n ...acc,\n [key]: action,\n };\n }, {});\n }\n}\n\n// Define an interface for the API returned by create()\nexport interface CrannAPI<TConfig extends AnyConfig> {\n get: {\n (): DerivedState<TConfig>;\n (key: string): DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>;\n };\n set: {\n (state: Partial<DerivedServiceState<TConfig>>): Promise<void>;\n (\n state: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n key: string\n ): Promise<void>;\n };\n subscribe: (\n listener: (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n ) => void;\n onInstanceReady: (\n listener: (instanceId: string, agent: AgentInfo) => void\n ) => () => void;\n findInstance: (location: BrowserLocation) => string | null;\n queryAgents: (query: Partial<BrowserLocation>) => Agent[];\n clear: () => Promise<void>;\n}\n\nexport function create<TConfig extends AnyConfig>(\n config: TConfig,\n options?: CrannOptions\n): CrannAPI<TConfig> {\n const instance = Crann.getInstance(config, options);\n\n return {\n get: instance.get.bind(instance),\n set: instance.set.bind(instance),\n subscribe: instance.subscribe.bind(instance),\n onInstanceReady: instance.subscribeToInstanceReady.bind(instance),\n findInstance: instance.findInstance.bind(instance),\n queryAgents: instance.queryAgents.bind(instance),\n clear: instance.clear.bind(instance),\n };\n}\n\nfunction isConfigItem(item: any): item is ConfigItem<any> {\n return item && typeof item === \"object\" && \"default\" in item;\n}\n", "import { AgentInfo, BrowserLocation } from \"porter-source\";\n\nexport const Partition = {\n Instance: \"instance\" as const,\n Service: \"service\" as const,\n};\n\nexport const Persistence = {\n Session: \"session\" as const,\n Local: \"local\" as const,\n None: \"none\" as const,\n};\n\nexport type ActionHandler<TState, TArgs extends any[], TResult> = (\n state: TState,\n setState: (newState: Partial<TState>) => Promise<void>,\n target: BrowserLocation,\n ...args: TArgs\n) => Promise<TResult>;\n\nexport type ActionDefinition<TState, TArgs extends any[], TResult> = {\n handler: ActionHandler<TState, TArgs, TResult>;\n validate?: (...args: TArgs) => void;\n};\n\nexport type ActionsConfig<TState> = {\n [K: string]: ActionDefinition<TState, any[], Partial<TState>>;\n};\n\n// Input types (what users provide in their config)\nexport type ConfigItem<T> = {\n default: T;\n partition?: (typeof Partition)[keyof typeof Partition];\n persist?: (typeof Persistence)[keyof typeof Persistence];\n};\n\nexport type AnyConfig = Record<\n string,\n ConfigItem<any> | ActionDefinition<any, any[], any>\n>;\n\n// Helper type to extract just the state items from a config\nexport type StateConfig<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> ? T[P] : never;\n};\n\n// Helper type to extract just the action items from a config\nexport type ActionConfig<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ActionDefinition<any, any[], any> ? T[P] : never;\n};\n\n// Update DerivedState to use the internal types\nexport type DerivedState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> ? T[P][\"default\"] : never;\n};\n\n// Update DerivedInstanceState to use the internal types\nexport type DerivedInstanceState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> & { partition: \"instance\" }\n ? T[P][\"default\"]\n : never;\n};\n\n// Update DerivedServiceState to use the internal types\nexport type DerivedServiceState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> & { partition: \"service\" }\n ? T[P][\"default\"]\n : never;\n};\n\n// Type guards\nexport const isStateItem = <T>(\n item: ConfigItem<T> | ActionDefinition<any, any[], any>\n): item is ConfigItem<T> => {\n return !(\"handler\" in item);\n};\n\nexport const isActionItem = <TState, TArgs extends any[], TResult>(\n item: ConfigItem<any> | ActionDefinition<TState, TArgs, TResult>\n): item is ActionDefinition<TState, TArgs, TResult> => {\n return \"handler\" in item;\n};\n\ntype StateSubscriber<TConfig extends AnyConfig> = {\n keys?: Array<keyof DerivedState<TConfig>>;\n callback: (changes: StateUpdate<TConfig>) => void;\n};\n\ntype CrannAgent<TConfig extends AnyConfig> = {\n get: () => DerivedState<TConfig>;\n set: (update: StateUpdate<TConfig>) => void;\n subscribe: (\n callback: (changes: StateUpdate<TConfig>) => void,\n keys?: Array<keyof TConfig>\n ) => () => void;\n getAgentInfo: () => AgentInfo;\n onReady: (callback: (info: ConnectionStatus) => void) => () => void;\n};\n\ntype UseCrann<TConfig extends AnyConfig> = <\n K extends keyof DerivedState<TConfig>\n>(\n key: K\n) => [\n DerivedState<TConfig>[K],\n (value: DerivedState<TConfig>[K]) => void,\n (callback: (update: StateChangeUpdate<TConfig, K>) => void) => () => void\n];\n\ntype ConnectReturn<TConfig extends AnyConfig> = {\n useCrann: UseCrann<TConfig>;\n get: CrannAgent<TConfig>[\"get\"];\n set: CrannAgent<TConfig>[\"set\"];\n subscribe: CrannAgent<TConfig>[\"subscribe\"];\n getAgentInfo: CrannAgent<TConfig>[\"getAgentInfo\"];\n onReady: CrannAgent<TConfig>[\"onReady\"];\n callAction: (name: string, ...args: any[]) => Promise<any>;\n};\n\ntype StateChangeUpdate<\n TConfig extends AnyConfig,\n K extends keyof DerivedState<TConfig>\n> = {\n current: DerivedState<TConfig>[K];\n previous: DerivedState<TConfig>[K];\n state: DerivedState<TConfig>;\n};\n\ntype AgentSubscription<TConfig extends AnyConfig> = {\n (\n callback: (changes: StateUpdate<TConfig>) => void,\n key?: keyof DerivedState<TConfig>\n ): number;\n};\n\ntype StateUpdate<TConfig extends AnyConfig> = Partial<DerivedState<TConfig>>;\n\nexport type CrannOptions = {\n debug?: boolean;\n storagePrefix?: string;\n};\n\ntype ConnectionStatus = {\n connected: boolean;\n agent?: AgentInfo;\n};\n\nexport type CrannConfig<TState> = {\n [K: string]: ConfigItem<any> | ActionsConfig<TState>;\n};\n\nexport {\n StateSubscriber,\n CrannAgent,\n AgentSubscription,\n StateUpdate,\n DerivedState as State,\n ConnectReturn,\n UseCrann,\n ConnectionStatus,\n StateChangeUpdate,\n};\n", "export function deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n\n if (a == null || typeof a !== 'object' || b == null || typeof b !== 'object') return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n keysA.sort();\n keysB.sort();\n\n for (let i = 0; i < keysA.length; i++) {\n const key = keysA[i];\n if (key !== keysB[i] || !deepEqual(a[key], b[key])) return false;\n }\n return true;\n}", "// Create a global debug state manager\nexport class DebugManager {\n private static _debug: boolean = false;\n\n static setDebug(value: boolean): void {\n DebugManager._debug = value;\n }\n\n static isDebugEnabled(): boolean {\n return DebugManager._debug;\n }\n}\n\n// Export a convenience function\nexport function isDebugEnabled(): boolean {\n return DebugManager.isDebugEnabled();\n}\n", "import { isDebugEnabled } from \"./debug\";\n\nexport type StateChangeMetadata = {\n source: string;\n timestamp: number;\n changes: any;\n instanceKey?: string;\n};\n\nexport function trackStateChange(\n target: any,\n propertyKey: string,\n descriptor: PropertyDescriptor\n): PropertyDescriptor {\n const originalMethod = descriptor.value;\n\n descriptor.value = function (...args: any[]) {\n // Only log if debugging is enabled\n if (isDebugEnabled()) {\n // Get the stack trace to find the actual caller\n const stack = new Error().stack;\n const lines = stack?.split(\"\\n\") || [];\n const callerMatch = lines[3]?.match(/at\\s+(\\S+)\\s+/);\n const caller = callerMatch ? callerMatch[1] : \"unknown\";\n\n const changes = args.length > 1 ? args[1] : undefined;\n\n const metadata: StateChangeMetadata = {\n source: caller,\n timestamp: Date.now(),\n instanceKey: args[0],\n changes,\n };\n\n console.log(`Crann State Change:`, metadata);\n }\n return originalMethod.apply(this, args);\n };\n\n return descriptor;\n}\n", "import { source, AgentInfo, connect, Message, AgentAPI } from \"porter-source\";\nimport { createEndpoint } from \"./endpoint\";\nimport { MessageEndpoint, CallMessage, RPCMessage } from \"./types\";\nimport { ActionsConfig } from \"../model/crann.model\";\nimport { Logger } from \"../utils/logger\";\nimport { getAgentTag } from \"../utils/agent\";\n\nexport function createCrannRPCAdapter<\n TState,\n TActions extends ActionsConfig<TState>\n>(\n initialState: TState,\n actions: TActions,\n porter?: ReturnType<typeof source> | ReturnType<typeof connect>,\n setState?: (newState: Partial<TState>) => Promise<void>\n) {\n const porterInstance = porter || source(\"crann\");\n\n // Determine if this is a service worker instance (source) or content script instance (connect)\n const isServiceWorker = !(porterInstance.type === \"agent\");\n\n // Set up logger with the appropriate context\n const logger = Logger.forContext(isServiceWorker ? \"Core:RPC\" : \"Agent:RPC\");\n\n const messageEndpoint: MessageEndpoint = {\n postMessage: (message, transferables) => {\n if (isServiceWorker) {\n logger.debug(\"Posting message from service worker:\", {\n message,\n transferables,\n });\n // In service worker, we need to respond to the specific target\n const [, rpcPayload] = message;\n const target = getTargetFromMessage(rpcPayload);\n if (!target) {\n logger.warn(\"No target specified for RPC response in service worker\");\n return;\n }\n porterInstance.post(\n {\n action: \"rpc\",\n payload: {\n message,\n transferables: transferables || [],\n },\n },\n target\n );\n } else {\n // In content script (agent) context\n // Get the agent info only when needed\n const agentInfo = (porterInstance as AgentAPI).getAgentInfo();\n\n if (!agentInfo) {\n logger.warn(\"No agent info found for posting message\", { agentInfo });\n return;\n }\n\n // Get the agent tag for logging\n const myTag = getAgentTag(agentInfo);\n\n // Destructure the tuple, skipping the messageId which we don't need\n const [, rpcPayload] = message;\n\n // Use type guard to check if it's a call message\n if (\"call\" in rpcPayload) {\n // Add the target info to the call message\n rpcPayload.call.target = agentInfo?.location;\n }\n\n logger.withTag(myTag).debug(\"Sending RPC message from agent:\", {\n rpcPayload,\n message,\n });\n // In content script, target is automatically the service worker\n porterInstance.post({\n action: \"rpc\",\n payload: {\n message,\n transferables: transferables || [],\n },\n });\n }\n },\n addEventListener: (event, listener) => {\n porterInstance.on({\n rpc: (message: Message<string>, info?: AgentInfo) => {\n try {\n if (!info) {\n logger.debug(\"RPC message received:\", {\n message,\n event,\n });\n } else {\n // Get the agent tag for logging\n const myTag = getAgentTag(info);\n logger.withTag(myTag).debug(\"RPC message received:\", {\n message,\n event,\n });\n }\n\n const { payload } = message;\n const { message: originalMessage, transferables = [] } = payload;\n const rpcEvent = new MessageEvent(\"message\", {\n data: originalMessage,\n ports:\n (transferables.filter(\n (t: unknown) => t instanceof MessagePort\n ) as MessagePort[]) || [],\n });\n listener(rpcEvent);\n } catch (e) {\n logger.error(\"Failed to parse RPC message payload:\", e);\n }\n },\n });\n },\n removeEventListener: () => {\n // Porter-source doesn't support removing listeners\n },\n // Add context information\n context: {\n isServiceWorker,\n agentInfo: !isServiceWorker\n ? (porterInstance as AgentAPI).getAgentInfo()\n : undefined,\n },\n };\n\n return createEndpoint(messageEndpoint, initialState, actions, setState);\n}\n\n// Don't love this being here. Let's move it sometime soon,\n// or find another way to do this.\nfunction getTargetFromMessage(payload: RPCMessage): any {\n if (\"result\" in payload) return payload.result.target;\n if (\"error\" in payload) return payload.error.target;\n if (\"call\" in payload) return payload.call.target;\n if (\"release\" in payload) return payload.release.target;\n return undefined;\n}\n", "export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport class Logger {\n private static debug = false;\n private static prefix = \"CrannLogger\";\n private static noOp = function () {};\n\n private context: string;\n private tag: string | null = null;\n\n /**\n * Create a new Logger instance with a specific context\n */\n constructor(context: string) {\n this.context = context;\n }\n\n static setDebug(value: boolean): void {\n Logger.debug = value;\n }\n\n static setPrefix(value: string): void {\n Logger.prefix = value;\n }\n\n /**\n * Set a persistent tag for this Logger instance\n */\n setTag(tag: string | null): void {\n this.tag = tag;\n }\n\n /**\n * Create a temporary logger with a specific tag\n * This doesn't modify the original logger instance\n */\n withTag(tag: string) {\n const tempLogger = new Logger(this.context);\n tempLogger.setTag(tag);\n return tempLogger;\n }\n\n /**\n * Get the full context string including tag if present\n */\n private getFullContext(): string {\n if (this.tag) {\n return `${this.context}:${this.tag}`;\n }\n return this.context;\n }\n\n /**\n * Create the log methods bound to the current context and tag\n */\n private createLogMethods() {\n const fullContext = this.getFullContext();\n const formatString = `%c${Logger.prefix}%c [%c${fullContext}%c]`;\n\n // Styles for the prefix and context - updated for better readability on dark backgrounds\n const prefixStyle = \"color: #3fcbff; font-weight: bold\"; // Bright cyan\n const contextStyle = \"color: #d58cff; font-weight: bold\"; // Bright purple\n const resetStyle = \"\";\n\n if (Logger.debug) {\n return {\n debug: console.log.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n log: console.log.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n info: console.info.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n warn: console.warn.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n error: console.error.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n };\n } else {\n return {\n debug: Logger.noOp,\n log: Logger.noOp,\n info: Logger.noOp,\n warn: Logger.noOp,\n error: Logger.noOp,\n };\n }\n }\n\n /**\n * Log methods that are dynamically created based on current context and tag\n */\n get debug() {\n return this.createLogMethods().debug;\n }\n get log() {\n return this.createLogMethods().log;\n }\n get info() {\n return this.createLogMethods().info;\n }\n get warn() {\n return this.createLogMethods().warn;\n }\n get error() {\n return this.createLogMethods().error;\n }\n\n /**\n * Static helper to create a logger with a specific context\n */\n static forContext(context: string, tag?: string): Logger {\n const logger = new Logger(context);\n if (tag) {\n logger.setTag(tag);\n }\n return logger;\n }\n}\n", "import { AgentInfo } from \"porter-source\";\n\n/**\n * Formats an agent tag based on the agent information\n * @param agent Agent information\n * @param options Configuration options\n * @returns Formatted agent tag string\n */\nexport function getAgentTag(\n agent: AgentInfo,\n options: { terse?: boolean } = { terse: true }\n): string {\n const formatTabId = (tabId: number | string): string => {\n const tabIdStr = String(tabId);\n if (tabIdStr.length >= 4) {\n return tabIdStr.slice(-4);\n } else {\n return tabIdStr.padStart(4, \"0\");\n }\n };\n\n const formattedTabId = formatTabId(agent.location.tabId);\n\n if (options?.terse) {\n return `${formattedTabId}:${agent.location.frameId}`;\n }\n return `${agent.location.context}:${formattedTabId}:${agent.location.frameId}`;\n}\n", "import { createBasicEncoder } from \"./encoding\";\nimport type {\n MessageEndpoint,\n RemoteCallable,\n EncodingStrategy,\n EncodingStrategyApi,\n Retainer,\n CallMessage,\n ResultMessage,\n ErrorMessage,\n RPCMessage,\n} from \"./types\";\nimport { ActionsConfig } from \"../model/crann.model\";\nimport { Logger } from \"../utils/logger\";\nimport { getAgentTag } from \"../utils/agent\";\n\nconst CALL = 0;\nconst RESULT = 1;\nconst TERMINATE = 2;\nconst RELEASE = 3;\nconst FUNCTION_APPLY = 5;\nconst FUNCTION_RESULT = 6;\n\ntype AnyFunction = (...args: any[]) => any;\n\nexport interface CreateEndpointOptions<T = unknown> {\n uuid?(): string;\n createEncoder?(api: EncodingStrategyApi): EncodingStrategy;\n callable?: (keyof T)[];\n}\n\nexport interface Endpoint<T> {\n readonly call: RemoteCallable<T>;\n replace(messenger: MessageEndpoint): void;\n expose(api: Record<string, AnyFunction | undefined>): void;\n callable(...methods: string[]): void;\n terminate(): void;\n}\n\n/**\n * An endpoint wraps around a messenger, acting as the intermediary for all\n * messages both send from, and received by, that messenger. The endpoint sends\n * all messages as arrays, where the first element is the message type, and the\n * second is the arguments for that message (as an array). For messages that send\n * meaningful content across the wire (e.g., arguments to function calls, return\n * results), the endpoint first encodes these values.\n *\n * Encoding is done using a CBOR-like encoding scheme. The value is encoded into\n * an array buffer, and is paired with an additional array buffer that contains all\n * the strings used in that message (in the encoded value, strings are encoded as\n * their index in the \"strings\" encoding to reduce the cost of heavily-duplicated\n * strings, which is more likely in payloads containing UI). This encoding also takes\n * care of encoding functions: it uses a \"tagged\" item in CBOR to represent a\n * function as a string ID, which the opposite endpoint will be capable of turning\n * into a consistent, memory-manageable function proxy.\n *\n * The main CBOR encoding is entirely take from the [cbor.js package](https://github.com/paroga/cbor-js).\n * The special behavior for encoding strings and functions was then added in to the\n * encoder and decoder. For additional details on CBOR:\n *\n * @see https://tools.ietf.org/html/rfc7049\n */\nexport function createEndpoint<TState, TActions extends ActionsConfig<TState>>(\n messenger: MessageEndpoint,\n state: TState,\n actions: TActions,\n setState?: (newState: Partial<TState>) => Promise<void>,\n encodingStrategy?: EncodingStrategy\n): RemoteCallable<TActions> {\n const callbacks = new Map<number, (result: unknown) => void>();\n const retainedObjects = new Map<string, Set<Retainer>>();\n\n // Create logger - will be used in Service Worker or Agent context based on the messenger's context\n const contextPrefix = messenger.context?.isServiceWorker ? \"Core\" : \"Agent\";\n const logger = Logger.forContext(`${contextPrefix}:RPC`);\n\n // If we have agent info, set the tag\n if (messenger.context?.agentInfo) {\n logger.setTag(getAgentTag(messenger.context.agentInfo));\n }\n\n messenger.addEventListener(\"message\", (event) => {\n logger.debug(\"Message received:\", event);\n const [id, message] = event.data as [number, RPCMessage];\n\n if (\"call\" in message && \"args\" in message.call) {\n logger.debug(\"Processing call message:\", message);\n const callMessage = message.call;\n const { id: callId, args, target } = callMessage;\n const action = actions[callId];\n if (!action) {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: \"Action not found\", target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n return;\n }\n\n try {\n if (action.validate) {\n action.validate(...args);\n }\n\n // Ensure we have a target - if not provided, we need to handle this case\n if (!target) {\n messenger.postMessage([\n id,\n {\n error: {\n id: callId,\n error: \"No target provided for action call\",\n target,\n },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n return;\n }\n\n // Handle both synchronous and asynchronous results\n Promise.resolve(action.handler(state, setState!, target, ...args)).then(\n (result: unknown) => {\n logger.debug(\"Action handler result:\", {\n result,\n target,\n });\n messenger.postMessage([\n id,\n { result: { id: callId, result, target } },\n ] as [number, ResultMessage]);\n },\n (error: Error) => {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: error.message, target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n }\n );\n } catch (error) {\n if (error instanceof Error) {\n messenger.postMessage([\n id,\n { error: { id: callId, error: error.message, target } },\n ] as [number, ErrorMessage]);\n } else {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: \"Unknown error occurred\", target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n }\n }\n } else if (\"result\" in message) {\n const resultMessage = message.result;\n const callback = callbacks.get(id);\n if (callback) {\n callback(resultMessage.result);\n callbacks.delete(id);\n }\n } else if (\"error\" in message) {\n const errorMessage = message.error;\n const callback = callbacks.get(id);\n if (callback) {\n callback(Promise.reject(new Error(errorMessage.error)));\n callbacks.delete(id);\n }\n } else if (\"release\" in message) {\n const releaseMessage = message.release;\n const retainers = retainedObjects.get(releaseMessage.id);\n if (retainers) {\n retainers.clear();\n retainedObjects.delete(releaseMessage.id);\n }\n }\n });\n\n const proxy = new Proxy({} as RemoteCallable<TActions>, {\n get(_, prop: string) {\n return (...args: unknown[]) => {\n const id = Math.random();\n return new Promise((resolve, reject) => {\n callbacks.set(id, (result) => {\n if (result instanceof Promise) {\n result.then(resolve, reject);\n } else {\n resolve(result);\n }\n });\n messenger.postMessage([id, { call: { id: prop, args } }] as [\n number,\n CallMessage\n ]);\n });\n };\n },\n });\n\n return proxy;\n}\n\nfunction defaultUuid() {\n return `${uuidSegment()}-${uuidSegment()}-${uuidSegment()}-${uuidSegment()}`;\n}\n\nfunction uuidSegment() {\n return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16);\n}\n\nfunction createCallable<T>(\n handlerForCall: (\n property: string | number | symbol\n ) => AnyFunction | undefined,\n callable?: (keyof T)[]\n): RemoteCallable<T> {\n let call: any;\n\n if (callable == null) {\n if (typeof Proxy !== \"function\") {\n throw new Error(\n `You must pass an array of callable methods in environments without Proxies.`\n );\n }\n\n const cache = new Map<string | number | symbol, AnyFunction | undefined>();\n\n call = new Proxy(\n {},\n {\n get(_target, property) {\n if (cache.has(property)) {\n return cache.get(property);\n }\n\n const handler = handlerForCall(property);\n cache.set(property, handler);\n return handler;\n },\n }\n );\n } else {\n call = {};\n\n for (const method of callable) {\n Object.defineProperty(call, method, {\n value: handlerForCall(method),\n writable: false,\n configurable: true,\n enumerable: true,\n });\n }\n }\n\n return call;\n}\n", "import {\n ConfigItem,\n DerivedState,\n StateSubscriber,\n ConnectReturn,\n UseCrann,\n ConnectionStatus,\n StateChangeUpdate,\n ActionDefinition,\n AnyConfig,\n isStateItem,\n isActionItem,\n} from \"./model/crann.model\";\nimport { AgentInfo, connect as connectPorter } from \"porter-source\";\nimport { createCrannRPCAdapter } from \"./rpc/adapter\";\nimport { Logger } from \"./utils/logger\";\nimport { getAgentTag } from \"./utils/agent\";\n\nlet connectionStatus: ConnectionStatus = { connected: false };\nlet crannInstance: unknown = null;\n\nexport function connect<TConfig extends AnyConfig>(\n config: TConfig,\n options?: { context?: string; debug?: boolean }\n): ConnectReturn<TConfig> {\n const debug = options?.debug || false;\n const context = options?.context;\n\n // Set up logger\n if (debug) {\n Logger.setDebug(true);\n }\n const logger = Logger.forContext(\"Agent\");\n\n let _myInfo: AgentInfo;\n let _myTag = \"unset\";\n const readyCallbacks = new Set<(info: ConnectionStatus) => void>();\n\n logger.log(\n \"Initializing Crann Agent\" + (context ? ` with context: ${context}` : \"\")\n );\n if (crannInstance) {\n logger.log(\"We had an instance already, returning\");\n\n if (connectionStatus.connected) {\n logger.log(\"Connect, calling onReady callback\");\n setTimeout(() => {\n readyCallbacks.forEach((callback) => callback(connectionStatus));\n }, 0);\n }\n return crannInstance as ConnectReturn<TConfig>;\n }\n\n logger.log(\"No existing instance, creating a new one\");\n const porter = connectPorter({\n namespace: \"crann\",\n debug: false,\n });\n\n logger.log(\"Porter connection created\");\n\n // Initialize RPC with empty actions since this is the client side\n const actions = Object.entries(config)\n .filter(([_, value]) => isActionItem(value))\n .reduce<\n Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>\n >((acc, [key, value]) => {\n const action = value as ActionDefinition<\n DerivedState<TConfig>,\n any[],\n any\n >;\n return {\n ...acc,\n [key]: {\n type: \"action\",\n handler: action.handler,\n validate: action.validate,\n },\n };\n }, {});\n\n const rpcEndpoint = createCrannRPCAdapter(\n getDerivedState(config),\n actions,\n porter\n );\n\n let initialStateReceived = false;\n\n porter.on({\n initialState: (message) => {\n logger.log(\"initialState received\", {\n alreadyReceived: initialStateReceived,\n payload: message.payload,\n });\n\n if (initialStateReceived) {\n logger.log(\"Ignoring duplicate initialState message\");\n return;\n }\n\n initialStateReceived = true;\n\n _state = message.payload.state;\n _myInfo = message.payload.info;\n _myTag = getAgentTag(_myInfo);\n connectionStatus = { connected: true, agent: _myInfo };\n\n // Update logger with the agent tag once we have it\n logger.setTag(_myTag);\n logger.log(\n `Initial state received and ${listeners.size} listeners notified`,\n {\n message,\n }\n );\n readyCallbacks.forEach((callback) => {\n logger.log(\"Calling onReady callbacks\");\n callback(connectionStatus);\n });\n listeners.forEach((listener) => {\n listener.callback(_state);\n });\n },\n stateUpdate: (message) => {\n changes = message.payload.state;\n _state = { ..._state, ...changes };\n logger.log(\"State updated:\", { message, changes, _state });\n if (!changes) return;\n\n listeners.forEach((listener) => {\n if (listener.keys === undefined) {\n listener.callback(changes!);\n } else {\n const matchFound = listener.keys.some((key) => key in changes!);\n if (matchFound) {\n listener.callback(changes!);\n }\n }\n });\n },\n });\n logger.log(\"Porter connected. Setting up state and listeners\");\n let _state = getDerivedState(config);\n let changes: Partial<DerivedState<TConfig>> | null = null;\n const listeners = new Set<StateSubscriber<TConfig>>();\n\n logger.log(\"Completed setup, returning instance\");\n\n const get = () => _state;\n const set = (newState: Partial<DerivedState<TConfig>>) => {\n logger.log(\"Calling post with setState\", newState);\n porter.post({ action: \"setState\", payload: { state: newState } });\n };\n\n const subscribe = (\n callback: (changes: Partial<DerivedState<TConfig>>) => void,\n keys?: Array<keyof DerivedState<TConfig>>\n ): (() => void) => {\n const listener = { keys, callback };\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n };\n\n const useCrann: UseCrann<TConfig> = <K extends keyof DerivedState<TConfig>>(\n key: K\n ) => {\n const getValue = () => {\n const value = get()[key];\n return value as TConfig[K] extends ConfigItem<any>\n ? TConfig[K][\"default\"]\n : never;\n };\n\n const setValue = (\n value: TConfig[K] extends ConfigItem<any> ? TConfig[K][\"default\"] : never\n ) => set({ [key]: value } as Partial<DerivedState<TConfig>>);\n\n const subscribeToChanges = (\n callback: (update: StateChangeUpdate<TConfig, K>) => void\n ) => {\n let previousValue = getValue();\n\n return subscribe(\n (changes) => {\n if (key in changes) {\n const currentValue = getValue();\n const fullState = get();\n callback({\n current: currentValue,\n previous: previousValue,\n state: fullState,\n } as StateChangeUpdate<TConfig, K>);\n previousValue = currentValue;\n }\n },\n [key]\n );\n };\n\n return [getValue(), setValue, subscribeToChanges];\n };\n\n const onReady = (callback: (info: ConnectionStatus) => void) => {\n logger.log(\"onReady callback added\");\n readyCallbacks.add(callback);\n if (connectionStatus.connected) {\n logger.log(\"calling onReady callback\");\n setTimeout(() => {\n callback(connectionStatus);\n }, 0);\n }\n return () => readyCallbacks.delete(callback);\n };\n\n const getAgentInfo = () => _myInfo;\n\n const callAction = async (name: string, ...args: any[]) => {\n logger.log(\"Calling action\", name, args);\n return (rpcEndpoint as any)[name](...args);\n };\n\n const instance = {\n useCrann,\n get,\n set,\n subscribe,\n getAgentInfo,\n onReady,\n callAction,\n };\n\n crannInstance = instance;\n\n return crannInstance as ConnectReturn<TConfig>;\n}\n\nexport function connected(): boolean {\n return crannInstance !== null;\n}\n\nfunction getDerivedState<TConfig extends AnyConfig>(\n config: TConfig\n): DerivedState<TConfig> {\n const state: any = {};\n Object.keys(config).forEach((key) => {\n const item = config[key];\n if (isStateItem(item)) {\n state[key] = item.default;\n }\n });\n return state;\n}\n", "import { useState, useEffect, useCallback, useMemo, useRef } from \"react\";\nimport {\n AnyConfig,\n ConfigItem,\n DerivedState,\n StateUpdate,\n} from \"../model/crann.model\";\nimport { connect } from \"../crannAgent\";\n\nexport function createCrannStateHook<TConfig extends AnyConfig>(\n config: TConfig\n) {\n return function useCrannState(context?: string) {\n const { useCrann, get, set, subscribe, callAction } = useMemo(() => {\n const instance = connect(config);\n return instance;\n }, [context]);\n\n const useStateItem = useCallback(\n <K extends keyof DerivedState<TConfig>>(key: K) => {\n const [value, setValue] = useState<DerivedState<TConfig>[K]>(\n get()[key]\n );\n const valueRef = useRef(value);\n\n useEffect(() => {\n valueRef.current = value;\n }, [value]);\n\n useEffect(() => {\n setValue(get()[key]);\n const unsubscribe = subscribe(\n (changes: StateUpdate<TConfig>) => {\n if (key in changes) {\n setValue(changes[key] as DerivedState<TConfig>[K]);\n }\n },\n [key]\n );\n return unsubscribe;\n }, [key]);\n\n const updateValue = useCallback(\n (newValue: DerivedState<TConfig>[K]) => {\n set({ [key]: newValue } as Partial<DerivedState<TConfig>>);\n },\n [key]\n );\n\n return [value, updateValue] as const;\n },\n [get, set, subscribe]\n );\n\n const getState = useCallback(() => get(), [get]);\n\n const setState = useCallback(\n (newState: Partial<DerivedState<TConfig>>) => {\n set(newState);\n },\n [set]\n );\n\n return {\n useStateItem,\n getState,\n setState,\n useCrann,\n callAction,\n };\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["src_exports", "__export", "Crann", "Partition", "Persistence", "connect", "connected", "create", "createCrannStateHook", "__toCommonJS", "import_webextension_polyfill", "Partition", "Persistence", "isStateItem", "item", "isActionItem", "import_porter_source", "deepEqual", "a", "b", "keysA", "keysB", "key", "_DebugManager", "value", "DebugManager", "isDebugEnabled", "trackStateChange", "target", "propertyKey", "descriptor", "originalMethod", "args", "_a", "isDebugEnabled", "stack", "callerMatch", "caller", "changes", "metadata", "import_porter_source", "_Logger", "context", "value", "tag", "tempLogger", "fullContext", "formatString", "prefixStyle", "contextStyle", "resetStyle", "logger", "Logger", "getAgentTag", "agent", "options", "formattedTabId", "tabId", "tabIdStr", "createEndpoint", "messenger", "state", "actions", "setState", "encodingStrategy", "_a", "_b", "callbacks", "retainedObjects", "contextPrefix", "logger", "Logger", "getAgentTag", "event", "id", "message", "callMessage", "callId", "args", "target", "action", "result", "error", "resultMessage", "callback", "errorMessage", "releaseMessage", "retainers", "_", "prop", "resolve", "reject", "createCrannRPCAdapter", "initialState", "actions", "porter", "setState", "porterInstance", "isServiceWorker", "logger", "Logger", "messageEndpoint", "message", "transferables", "rpcPayload", "target", "getTargetFromMessage", "agentInfo", "myTag", "getAgentTag", "event", "listener", "info", "payload", "originalMessage", "rpcEvent", "t", "e", "createEndpoint", "_Crann", "config", "options", "DebugManager", "Logger", "message", "info", "agentTag", "getAgentTag", "agentsInitialized", "fullState", "actions", "createCrannRPCAdapter", "newState", "key", "initialInstanceState", "state", "update", "deepEqual", "currentState", "wasPersisted", "persistence", "value", "browser", "_", "listener", "changes", "agent", "location", "instance", "query", "worker", "itemKey", "item", "isConfigItem", "instanceItemKey", "instanceState", "Partition", "serviceItemKey", "serviceState", "local", "session", "combined", "hadItems", "prefixedKey", "isStateItem", "instanceId", "index", "isActionItem", "acc", "action", "__decorateClass", "trackStateChange", "Crann", "create", "import_porter_source", "connectionStatus", "crannInstance", "connect", "config", "options", "debug", "context", "Logger", "logger", "_myInfo", "_myTag", "readyCallbacks", "callback", "porter", "connectPorter", "actions", "_", "value", "isActionItem", "acc", "key", "action", "rpcEndpoint", "createCrannRPCAdapter", "getDerivedState", "initialStateReceived", "message", "_state", "getAgentTag", "listeners", "listener", "changes", "get", "set", "newState", "subscribe", "keys", "getValue", "setValue", "subscribeToChanges", "previousValue", "currentValue", "fullState", "name", "args", "connected", "state", "item", "isStateItem", "import_react", "createCrannStateHook", "config", "context", "useCrann", "get", "set", "subscribe", "callAction", "connect", "useStateItem", "key", "value", "setValue", "valueRef", "changes", "updateValue", "newValue", "getState", "setState", "newState"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/crann.ts", "../../src/model/crann.model.ts", "../../src/utils/deepEqual.ts", "../../src/utils/debug.ts", "../../src/utils/tracking.ts", "../../src/rpc/adapter.ts", "../../src/utils/logger.ts", "../../src/utils/agent.ts", "../../src/rpc/endpoint.ts", "../../src/crannAgent.ts", "../../src/hooks/useCrannState.ts"],
4
- "sourcesContent": ["import browser from \"webextension-polyfill\";\nimport {\n DerivedInstanceState,\n DerivedServiceState,\n ConfigItem,\n DerivedState,\n Partition,\n CrannOptions,\n ActionDefinition,\n AnyConfig,\n isStateItem,\n isActionItem,\n} from \"./model/crann.model\";\nimport { AgentInfo, source, Agent } from \"porter-source\";\nimport { deepEqual } from \"./utils/deepEqual\";\nimport { BrowserLocation } from \"porter-source\";\nimport { trackStateChange } from \"./utils/tracking\";\nimport { DebugManager } from \"./utils/debug\";\nimport { createCrannRPCAdapter } from \"./rpc/adapter\";\nimport { Logger } from \"./utils/logger\";\nimport { getAgentTag } from \"./utils/agent\";\n\nexport class Crann<TConfig extends AnyConfig> {\n private static instance: Crann<any> | null = null;\n private instances: Map<string, DerivedInstanceState<TConfig>> = new Map();\n private defaultServiceState: DerivedServiceState<TConfig>;\n private defaultInstanceState: DerivedInstanceState<TConfig>;\n private serviceState: DerivedServiceState<TConfig>;\n private stateChangeListeners: Array<\n (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedServiceState<TConfig> & DerivedInstanceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n > = [];\n private instanceReadyListeners: Array<\n (instanceId: string, agent: AgentInfo) => void\n > = [];\n private storagePrefix = \"crann_\";\n private porter = source(\"crann\", { debug: false });\n private rpcEndpoint: ReturnType<typeof createCrannRPCAdapter>;\n private logger: Logger;\n\n constructor(private config: TConfig, options?: CrannOptions) {\n // Set the debug flag globally\n if (options?.debug) {\n DebugManager.setDebug(true);\n Logger.setDebug(true);\n }\n this.storagePrefix = options?.storagePrefix ?? this.storagePrefix;\n\n // Set up the core logger\n this.logger = Logger.forContext(\"Core\");\n this.logger.log(\"Constructing Crann with new logger\");\n\n // Hydrate the initial state from the config defaults and from storage\n this.defaultInstanceState = this.initializeInstanceDefault();\n this.defaultServiceState = this.serviceState =\n this.initializeServiceDefault();\n this.hydrate();\n\n // Set up the message handlers\n this.logger.log(\"Crann constructed, setting initial message handlers\");\n this.porter.on({\n setState: (message, info) => {\n if (!info) {\n this.logger.warn(\"setState message heard from unknown agent\");\n return;\n }\n\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Setting state:\", message);\n this.set(message.payload.state, info.id);\n },\n });\n\n // Track which agents we've already sent initialState to\n const agentsInitialized = new Set<string>();\n\n // Once the agents are connected and have set up their listeners, send them the initial state\n this.porter.onMessagesSet((info: AgentInfo) => {\n if (!info) {\n this.logger.error(\"Messages set but no agent info.\", { info });\n return;\n }\n\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"onMessagesSet received for agent:\", {\n id: info.id,\n context: info.location.context,\n tabId: info.location.tabId,\n frameId: info.location.frameId,\n alreadyInitialized: agentsInitialized.has(info.id),\n });\n\n // Skip sending initialState if we've already sent it to this agent\n if (agentsInitialized.has(info.id)) {\n this.logger\n .withTag(agentTag)\n .log(\"Already sent initialState to agent, skipping:\", info.id);\n return;\n }\n\n // Add the agent to the set of agents we've already sent initialState to\n agentsInitialized.add(info.id);\n\n this.logger\n .withTag(agentTag)\n .log(\"Messages set received. Sending initial state.\", { info });\n const fullState = this.get(info.id);\n this.porter.post(\n {\n action: \"initialState\",\n payload: { state: fullState, info },\n },\n info.location\n );\n\n this.notifyInstanceReady(info.id, info);\n });\n\n // Handle agent connection and disconnection\n this.porter.onConnect((info: AgentInfo) => {\n if (!info) {\n this.logger.error(\"Agent connected but no agent info.\", { info });\n return;\n }\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Agent connected\", { info });\n this.addInstance(info.id, agentTag);\n this.porter.onDisconnect((info: AgentInfo) => {\n this.logger\n .withTag(getAgentTag(info))\n .log(\n \"Agent disconnect heard. Connection type, context and location:\",\n { info }\n );\n this.removeInstance(info.id);\n });\n });\n\n // Initialize RPC with actions\n const actions = this.extractActions(config);\n this.rpcEndpoint = createCrannRPCAdapter(\n this.get(),\n actions,\n this.porter,\n (newState: Partial<DerivedState<TConfig>>) => this.set(newState)\n );\n }\n\n public static getInstance<TConfig extends AnyConfig>(\n config: TConfig,\n options?: CrannOptions\n ): Crann<TConfig> {\n if (!Crann.instance) {\n Crann.instance = new Crann(config, options);\n } else if (options?.debug) {\n const logger = Logger.forContext(\"Core\");\n logger.log(\"Instance requested and already existed, returning\");\n }\n return Crann.instance;\n }\n\n /**\n * Add an instance to the Crann instance.\n * @param key The key of the instance to add.\n * @param agentTag The tag of the agent that is adding the instance, for logging.\n */\n private async addInstance(key: string, agentTag: string): Promise<void> {\n if (!this.instances.has(key)) {\n this.logger.withTag(agentTag).log(\"Adding instance from agent key\");\n const initialInstanceState = {\n ...this.defaultInstanceState,\n } as DerivedInstanceState<TConfig>;\n this.instances.set(key, initialInstanceState);\n } else {\n this.logger\n .withTag(agentTag)\n .log(\"Instance was already registered, ignoring request from key\");\n }\n }\n\n private async removeInstance(key: string): Promise<void> {\n if (this.instances.has(key)) {\n this.logger.withTag(key).log(\"Remove instance requested\");\n this.instances.delete(key);\n } else {\n this.logger\n .withTag(key)\n .log(\"Remove instance requested but it did not exist!\");\n }\n }\n\n @trackStateChange\n public async setServiceState(\n state: Partial<DerivedServiceState<TConfig>>\n ): Promise<void> {\n this.logger.log(\"Request to set service state with:\", state);\n const update = { ...this.serviceState, ...state };\n if (!deepEqual(this.serviceState, update)) {\n this.logger.log(\n \"Confirmed new state was different than existing so proceeding to persist then notify all connected instances.\"\n );\n this.serviceState = update;\n await this.persist(state);\n this.notify(state as Partial<DerivedState<TConfig>>);\n } else {\n this.logger.log(\"New state seems to be the same as existing, skipping\");\n }\n }\n\n @trackStateChange\n public async setInstanceState(\n key: string,\n state: Partial<DerivedInstanceState<TConfig>>\n ): Promise<void> {\n this.logger\n .withTag(key)\n .log(\"Request to update instance state, update:\", state);\n const currentState = this.instances.get(key) || this.defaultInstanceState;\n const update = { ...currentState, ...state };\n if (!deepEqual(currentState, update)) {\n this.logger\n .withTag(key)\n .log(\"Instance state update is different, updating and notifying.\");\n this.instances.set(key, update);\n this.notify(state as Partial<DerivedState<TConfig>>, key);\n } else {\n this.logger\n .withTag(key)\n .log(\"Instance state update is not different, skipping update.\");\n }\n }\n\n // If we pass in specific state to persist, it only persists that state.\n // Otherwise persists all of the worker state.\n private async persist(\n state?: Partial<DerivedServiceState<TConfig>>\n ): Promise<void> {\n this.logger.log(\"Persisting state\");\n let wasPersisted = false;\n for (const key in state || this.serviceState) {\n const item = this.config[key] as ConfigItem<any>;\n const persistence = item.persist || \"none\";\n const value = state\n ? state[key as keyof DerivedServiceState<TConfig>]\n : this.serviceState[key];\n switch (persistence) {\n case \"session\":\n await browser.storage.session.set({\n [this.storagePrefix + (key as string)]: value,\n });\n wasPersisted = true;\n break;\n case \"local\":\n await browser.storage.local.set({\n [this.storagePrefix + (key as string)]: value,\n });\n wasPersisted = true;\n break;\n default:\n break;\n }\n }\n if (wasPersisted) {\n this.logger.log(\"State was persisted\");\n } else {\n this.logger.log(\"Nothing to persist\");\n }\n }\n\n public async clear(): Promise<void> {\n this.logger.log(\"Clearing state\");\n this.serviceState = this.defaultServiceState;\n this.instances.forEach((_, key) => {\n this.instances.set(key, this.defaultInstanceState);\n });\n await this.persist();\n this.notify({});\n }\n\n public subscribe(\n listener: (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n ): void {\n this.logger.log(\"Subscribing to state\");\n this.stateChangeListeners.push(listener);\n }\n\n // Right now we notify the instance even if the state change came from the instance.\n // This should probably be skipped for instance state, since it already knows.\n private notify(changes: Partial<DerivedState<TConfig>>, key?: string): void {\n const agent = key ? this.porter.getAgentById(key) : undefined;\n const state = key ? this.get(key) : this.get();\n\n if (this.stateChangeListeners.length > 0) {\n this.logger.log(\"Notifying state change listeners in source\");\n this.stateChangeListeners.forEach((listener) => {\n listener(state, changes, agent?.info);\n });\n }\n\n if (key && agent?.info.location) {\n this.logger.withTag(key).log(\"Notifying of state change.\");\n this.porter.post(\n { action: \"stateUpdate\", payload: { state: changes } },\n agent.info.location\n );\n } else {\n this.logger.log(\"Notifying everyone\");\n // for every key of this.instances, post the state update to the corresponding key\n this.instances.forEach((_, key) => {\n this.porter.post(\n { action: \"stateUpdate\", payload: { state: changes } },\n key\n );\n });\n }\n }\n\n public get(): DerivedState<TConfig>;\n public get(\n key: string\n ): DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>;\n public get(\n key?: string\n ): DerivedServiceState<TConfig> | DerivedState<TConfig> {\n if (!key) {\n return { ...this.serviceState, ...({} as DerivedInstanceState<TConfig>) };\n }\n return { ...this.serviceState, ...this.instances.get(key) };\n }\n\n // Todo: Should we return the instance data? What is the point of this.\n public findInstance(location: BrowserLocation): string | null {\n const agent = this.porter.getAgentByLocation(location);\n if (!agent) {\n this.logger.log(\"Could not find agent for location:\", { location });\n return null;\n }\n for (const [key, instance] of this.instances) {\n if (key === agent.info.id) {\n this.logger.log(\"Found instance for key:\", key);\n return key;\n }\n }\n this.logger.log(\"Could not find instance for context and location:\", {\n location,\n });\n return null;\n }\n\n // Convenience re-export of the porter-source queryAgents method.\n public queryAgents(query: Partial<BrowserLocation>): Agent[] {\n return this.porter.queryAgents(query);\n }\n\n public async set(state: Partial<DerivedServiceState<TConfig>>): Promise<void>;\n public async set(\n state: Partial<DerivedInstanceState<TConfig>>,\n key: string\n ): Promise<void>;\n public async set(\n state: Partial<DerivedState<TConfig>>,\n key?: string\n ): Promise<void> {\n const instance = {} as Partial<DerivedInstanceState<TConfig>>;\n const worker = {} as Partial<DerivedServiceState<TConfig>>;\n\n for (const itemKey in state) {\n const item = this.config[itemKey as keyof TConfig];\n if (isConfigItem(item)) {\n if (item.partition === \"instance\") {\n const instanceItemKey =\n itemKey as keyof DerivedInstanceState<TConfig>;\n const instanceState = state as Partial<DerivedInstanceState<TConfig>>;\n instance[instanceItemKey] = instanceState[instanceItemKey];\n } else if (!item.partition || item.partition === Partition.Service) {\n const serviceItemKey = itemKey as keyof DerivedServiceState<TConfig>;\n const serviceState = state as Partial<DerivedServiceState<TConfig>>;\n worker[serviceItemKey] = serviceState[serviceItemKey]!;\n }\n }\n }\n\n if (key && Object.keys(instance).length > 0) {\n this.logger.withTag(key).log(\"Setting instance state:\", instance);\n this.setInstanceState(key, instance);\n }\n if (Object.keys(worker).length > 0) {\n this.logger.log(\"Setting service state:\", worker);\n this.setServiceState(worker);\n }\n }\n\n private async hydrate(): Promise<void> {\n this.logger.log(\"Hydrating state from storage.\");\n const local = await browser.storage.local.get(null);\n const session = await browser.storage.session.get(null);\n const combined = { ...local, ...session };\n const update: Partial<DerivedServiceState<TConfig>> = {}; // Cast update as Partial<DerivedState<TConfig>>\n let hadItems = false;\n for (const prefixedKey in combined) {\n const key = this.removePrefix(prefixedKey);\n if (this.config.hasOwnProperty(key)) {\n const value = combined[key];\n update[key as keyof DerivedServiceState<TConfig>] = value;\n hadItems = true;\n }\n }\n if (hadItems) {\n this.logger.log(\"Hydrated some items.\");\n } else {\n this.logger.log(\"No items found in storage.\");\n }\n this.serviceState = { ...this.defaultServiceState, ...update };\n }\n\n private removePrefix(key: string): string {\n if (key.startsWith(this.storagePrefix)) {\n return key.replace(this.storagePrefix, \"\");\n }\n return key;\n }\n\n private initializeInstanceDefault(): DerivedInstanceState<TConfig> {\n const instanceState: any = {};\n Object.keys(this.config).forEach((key) => {\n const item = this.config[key];\n if (isStateItem(item) && item.partition === \"instance\") {\n instanceState[key] = item.default;\n }\n });\n return instanceState;\n }\n\n private initializeServiceDefault(): DerivedServiceState<TConfig> {\n const serviceState: any = {};\n Object.keys(this.config).forEach((key) => {\n const item = this.config[key];\n if (\n isStateItem(item) &&\n (!item.partition || item.partition === Partition.Service)\n ) {\n serviceState[key] = item.default;\n }\n });\n return serviceState;\n }\n\n public subscribeToInstanceReady(\n listener: (instanceId: string, agent: AgentInfo) => void\n ): () => void {\n this.logger.log(\"Subscribing to instance ready events\");\n this.instanceReadyListeners.push(listener);\n\n this.instances.forEach((_, instanceId) => {\n const agent = this.porter.getAgentById(instanceId);\n if (agent?.info) {\n listener(instanceId, agent.info);\n }\n });\n\n return () => {\n this.logger.log(\"Unsubscribing from instance ready events\");\n const index = this.instanceReadyListeners.indexOf(listener);\n if (index !== -1) {\n this.instanceReadyListeners.splice(index, 1);\n }\n };\n }\n\n private notifyInstanceReady(instanceId: string, info: AgentInfo): void {\n if (this.instanceReadyListeners.length > 0) {\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Notifying instance ready listeners\");\n this.instanceReadyListeners.forEach((listener) => {\n listener(instanceId, info);\n });\n }\n }\n\n private extractActions(\n config: TConfig\n ): Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>> {\n return Object.entries(config)\n .filter(([_, value]) => isActionItem(value))\n .reduce<\n Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>\n >((acc, [key, value]) => {\n const action = value as ActionDefinition<\n DerivedState<TConfig>,\n any[],\n any\n >;\n return {\n ...acc,\n [key]: action,\n };\n }, {});\n }\n}\n\n// Define an interface for the API returned by create()\nexport interface CrannAPI<TConfig extends AnyConfig> {\n get: {\n (): DerivedState<TConfig>;\n (key: string): DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>;\n };\n set: {\n (state: Partial<DerivedServiceState<TConfig>>): Promise<void>;\n (\n state: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n key: string\n ): Promise<void>;\n };\n subscribe: (\n listener: (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n ) => void;\n onInstanceReady: (\n listener: (instanceId: string, agent: AgentInfo) => void\n ) => () => void;\n findInstance: (location: BrowserLocation) => string | null;\n queryAgents: (query: Partial<BrowserLocation>) => Agent[];\n clear: () => Promise<void>;\n}\n\nexport function create<TConfig extends AnyConfig>(\n config: TConfig,\n options?: CrannOptions\n): CrannAPI<TConfig> {\n const instance = Crann.getInstance(config, options);\n\n return {\n get: instance.get.bind(instance),\n set: instance.set.bind(instance),\n subscribe: instance.subscribe.bind(instance),\n onInstanceReady: instance.subscribeToInstanceReady.bind(instance),\n findInstance: instance.findInstance.bind(instance),\n queryAgents: instance.queryAgents.bind(instance),\n clear: instance.clear.bind(instance),\n };\n}\n\nfunction isConfigItem(item: any): item is ConfigItem<any> {\n return item && typeof item === \"object\" && \"default\" in item;\n}\n", "import { AgentInfo, BrowserLocation } from \"porter-source\";\n\nexport const Partition = {\n Instance: \"instance\" as const,\n Service: \"service\" as const,\n};\n\nexport const Persistence = {\n Session: \"session\" as const,\n Local: \"local\" as const,\n None: \"none\" as const,\n};\n\nexport type ActionHandler<TState, TArgs extends any[], TResult> = (\n state: TState,\n setState: (newState: Partial<TState>) => Promise<void>,\n target: BrowserLocation,\n ...args: TArgs\n) => Promise<TResult>;\n\nexport type ActionDefinition<TState, TArgs extends any[], TResult> = {\n handler: ActionHandler<TState, TArgs, TResult>;\n validate?: (...args: TArgs) => void;\n};\n\nexport type ActionsConfig<TState> = {\n [K: string]: ActionDefinition<TState, any[], Partial<TState>>;\n};\n\n// Input types (what users provide in their config)\nexport type ConfigItem<T> = {\n default: T;\n partition?: (typeof Partition)[keyof typeof Partition];\n persist?: (typeof Persistence)[keyof typeof Persistence];\n};\n\nexport type AnyConfig = Record<\n string,\n ConfigItem<any> | ActionDefinition<any, any[], any>\n>;\n\n// Helper type to extract just the state items from a config\nexport type StateConfig<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> ? T[P] : never;\n};\n\n// Helper type to extract just the action items from a config\nexport type ActionConfig<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ActionDefinition<any, any[], any> ? T[P] : never;\n};\n\n// Update DerivedState to use the internal types\nexport type DerivedState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> ? T[P][\"default\"] : never;\n};\n\n// Update DerivedInstanceState to use the internal types\nexport type DerivedInstanceState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> & { partition: \"instance\" }\n ? T[P][\"default\"]\n : never;\n};\n\n// Update DerivedServiceState to use the internal types\nexport type DerivedServiceState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> & { partition: \"service\" }\n ? T[P][\"default\"]\n : never;\n};\n\n// Type guards\nexport const isStateItem = <T>(\n item: ConfigItem<T> | ActionDefinition<any, any[], any>\n): item is ConfigItem<T> => {\n return !(\"handler\" in item);\n};\n\nexport const isActionItem = <TState, TArgs extends any[], TResult>(\n item: ConfigItem<any> | ActionDefinition<TState, TArgs, TResult>\n): item is ActionDefinition<TState, TArgs, TResult> => {\n return \"handler\" in item;\n};\n\ntype StateSubscriber<TConfig extends AnyConfig> = {\n keys?: Array<keyof DerivedState<TConfig>>;\n callback: (changes: StateUpdate<TConfig>) => void;\n};\n\ntype CrannAgent<TConfig extends AnyConfig> = {\n get: () => DerivedState<TConfig>;\n set: (update: StateUpdate<TConfig>) => void;\n subscribe: (\n callback: (changes: StateUpdate<TConfig>) => void,\n keys?: Array<keyof TConfig>\n ) => () => void;\n getAgentInfo: () => AgentInfo;\n onReady: (callback: (info: ConnectionStatus) => void) => () => void;\n};\n\ntype UseCrann<TConfig extends AnyConfig> = <\n K extends keyof DerivedState<TConfig>\n>(\n key: K\n) => [\n DerivedState<TConfig>[K],\n (value: DerivedState<TConfig>[K]) => void,\n (callback: (update: StateChangeUpdate<TConfig, K>) => void) => () => void\n];\n\ntype ConnectReturn<TConfig extends AnyConfig> = {\n useCrann: UseCrann<TConfig>;\n get: CrannAgent<TConfig>[\"get\"];\n set: CrannAgent<TConfig>[\"set\"];\n subscribe: CrannAgent<TConfig>[\"subscribe\"];\n getAgentInfo: CrannAgent<TConfig>[\"getAgentInfo\"];\n onReady: CrannAgent<TConfig>[\"onReady\"];\n callAction: (name: string, ...args: any[]) => Promise<any>;\n};\n\ntype StateChangeUpdate<\n TConfig extends AnyConfig,\n K extends keyof DerivedState<TConfig>\n> = {\n current: DerivedState<TConfig>[K];\n previous: DerivedState<TConfig>[K];\n state: DerivedState<TConfig>;\n};\n\ntype AgentSubscription<TConfig extends AnyConfig> = {\n (\n callback: (changes: StateUpdate<TConfig>) => void,\n key?: keyof DerivedState<TConfig>\n ): number;\n};\n\ntype StateUpdate<TConfig extends AnyConfig> = Partial<DerivedState<TConfig>>;\n\nexport type CrannOptions = {\n debug?: boolean;\n storagePrefix?: string;\n};\n\ntype ConnectionStatus = {\n connected: boolean;\n agent?: AgentInfo;\n};\n\nexport type CrannConfig<TState> = {\n [K: string]: ConfigItem<any> | ActionsConfig<TState>;\n};\n\nexport {\n StateSubscriber,\n CrannAgent,\n AgentSubscription,\n StateUpdate,\n DerivedState as State,\n ConnectReturn,\n UseCrann,\n ConnectionStatus,\n StateChangeUpdate,\n};\n", "export function deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n\n if (a == null || typeof a !== 'object' || b == null || typeof b !== 'object') return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n keysA.sort();\n keysB.sort();\n\n for (let i = 0; i < keysA.length; i++) {\n const key = keysA[i];\n if (key !== keysB[i] || !deepEqual(a[key], b[key])) return false;\n }\n return true;\n}", "// Create a global debug state manager\nexport class DebugManager {\n private static _debug: boolean = false;\n\n static setDebug(value: boolean): void {\n DebugManager._debug = value;\n }\n\n static isDebugEnabled(): boolean {\n return DebugManager._debug;\n }\n}\n\n// Export a convenience function\nexport function isDebugEnabled(): boolean {\n return DebugManager.isDebugEnabled();\n}\n", "import { isDebugEnabled } from \"./debug\";\n\nexport type StateChangeMetadata = {\n source: string;\n timestamp: number;\n changes: any;\n instanceKey?: string;\n};\n\nexport function trackStateChange(\n target: any,\n propertyKey: string,\n descriptor: PropertyDescriptor\n): PropertyDescriptor {\n const originalMethod = descriptor.value;\n\n descriptor.value = function (...args: any[]) {\n // Only log if debugging is enabled\n if (isDebugEnabled()) {\n // Get the stack trace to find the actual caller\n const stack = new Error().stack;\n const lines = stack?.split(\"\\n\") || [];\n const callerMatch = lines[3]?.match(/at\\s+(\\S+)\\s+/);\n const caller = callerMatch ? callerMatch[1] : \"unknown\";\n\n const changes = args.length > 1 ? args[1] : undefined;\n\n const metadata: StateChangeMetadata = {\n source: caller,\n timestamp: Date.now(),\n instanceKey: args[0],\n changes,\n };\n\n console.log(`Crann State Change:`, metadata);\n }\n return originalMethod.apply(this, args);\n };\n\n return descriptor;\n}\n", "import { source, AgentInfo, connect, Message, AgentAPI } from \"porter-source\";\nimport { createEndpoint } from \"./endpoint\";\nimport { MessageEndpoint, CallMessage, RPCMessage } from \"./types\";\nimport { ActionsConfig } from \"../model/crann.model\";\nimport { Logger } from \"../utils/logger\";\nimport { getAgentTag } from \"../utils/agent\";\n\nexport function createCrannRPCAdapter<\n TState,\n TActions extends ActionsConfig<TState>\n>(\n initialState: TState,\n actions: TActions,\n porter?: ReturnType<typeof source> | ReturnType<typeof connect>,\n setState?: (newState: Partial<TState>) => Promise<void>\n) {\n const porterInstance = porter || source(\"crann\");\n\n // Determine if this is a service worker instance (source) or content script instance (connect)\n const isServiceWorker = !(porterInstance.type === \"agent\");\n\n // Set up logger with the appropriate context\n const logger = Logger.forContext(isServiceWorker ? \"Core:RPC\" : \"Agent:RPC\");\n\n const messageEndpoint: MessageEndpoint = {\n postMessage: (message, transferables) => {\n if (isServiceWorker) {\n logger.debug(\"Posting message from service worker:\", {\n message,\n transferables,\n });\n // In service worker, we need to respond to the specific target\n const [, rpcPayload] = message;\n const target = getTargetFromMessage(rpcPayload);\n if (!target) {\n logger.warn(\"No target specified for RPC response in service worker\");\n return;\n }\n porterInstance.post(\n {\n action: \"rpc\",\n payload: {\n message,\n transferables: transferables || [],\n },\n },\n target\n );\n } else {\n // In content script (agent) context\n // Get the agent info only when needed\n const agentInfo = (porterInstance as AgentAPI).getAgentInfo();\n\n if (!agentInfo) {\n logger.warn(\"No agent info found for posting message\", { agentInfo });\n return;\n }\n\n // Get the agent tag for logging\n const myTag = getAgentTag(agentInfo);\n\n // Destructure the tuple, skipping the messageId which we don't need\n const [, rpcPayload] = message;\n\n // Use type guard to check if it's a call message\n if (\"call\" in rpcPayload) {\n // Add the target info to the call message\n rpcPayload.call.target = agentInfo?.location;\n }\n\n logger.withTag(myTag).debug(\"Sending RPC message from agent:\", {\n rpcPayload,\n message,\n });\n // In content script, target is automatically the service worker\n porterInstance.post({\n action: \"rpc\",\n payload: {\n message,\n transferables: transferables || [],\n },\n });\n }\n },\n addEventListener: (event, listener) => {\n porterInstance.on({\n rpc: (message: Message<string>, info?: AgentInfo) => {\n try {\n if (!info) {\n logger.debug(\"RPC message received:\", {\n message,\n event,\n });\n } else {\n // Get the agent tag for logging\n const myTag = getAgentTag(info);\n logger.withTag(myTag).debug(\"RPC message received:\", {\n message,\n event,\n });\n }\n\n const { payload } = message;\n const { message: originalMessage, transferables = [] } = payload;\n const rpcEvent = new MessageEvent(\"message\", {\n data: originalMessage,\n ports:\n (transferables.filter(\n (t: unknown) => t instanceof MessagePort\n ) as MessagePort[]) || [],\n });\n listener(rpcEvent);\n } catch (e) {\n logger.error(\"Failed to parse RPC message payload:\", e);\n }\n },\n });\n },\n removeEventListener: () => {\n // Porter-source doesn't support removing listeners\n },\n // Add context information\n context: {\n isServiceWorker,\n agentInfo: !isServiceWorker\n ? (porterInstance as AgentAPI).getAgentInfo()\n : undefined,\n },\n };\n\n return createEndpoint(messageEndpoint, initialState, actions, setState);\n}\n\n// Don't love this being here. Let's move it sometime soon,\n// or find another way to do this.\nfunction getTargetFromMessage(payload: RPCMessage): any {\n if (\"result\" in payload) return payload.result.target;\n if (\"error\" in payload) return payload.error.target;\n if (\"call\" in payload) return payload.call.target;\n if (\"release\" in payload) return payload.release.target;\n return undefined;\n}\n", "export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport class Logger {\n private static debug = false;\n private static prefix = \"CrannLogger\";\n private static noOp = function () {};\n\n private context: string;\n private tag: string | null = null;\n\n /**\n * Create a new Logger instance with a specific context\n */\n constructor(context: string) {\n this.context = context;\n }\n\n static setDebug(value: boolean): void {\n Logger.debug = value;\n }\n\n static setPrefix(value: string): void {\n Logger.prefix = value;\n }\n\n /**\n * Set a persistent tag for this Logger instance\n */\n setTag(tag: string | null): void {\n this.tag = tag;\n }\n\n /**\n * Create a temporary logger with a specific tag\n * This doesn't modify the original logger instance\n */\n withTag(tag: string) {\n const tempLogger = new Logger(this.context);\n tempLogger.setTag(tag);\n return tempLogger;\n }\n\n /**\n * Get the full context string including tag if present\n */\n private getFullContext(): string {\n if (this.tag) {\n return `${this.context}:${this.tag}`;\n }\n return this.context;\n }\n\n /**\n * Create the log methods bound to the current context and tag\n */\n private createLogMethods() {\n const fullContext = this.getFullContext();\n const formatString = `%c${Logger.prefix}%c [%c${fullContext}%c]`;\n\n // Styles for the prefix and context - updated for better readability on dark backgrounds\n const prefixStyle = \"color: #3fcbff; font-weight: bold\"; // Bright cyan\n const contextStyle = \"color: #d58cff; font-weight: bold\"; // Bright purple\n const resetStyle = \"\";\n\n if (Logger.debug) {\n return {\n debug: console.log.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n log: console.log.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n info: console.info.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n warn: console.warn.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n error: console.error.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n };\n } else {\n return {\n debug: Logger.noOp,\n log: Logger.noOp,\n info: Logger.noOp,\n warn: Logger.noOp,\n error: Logger.noOp,\n };\n }\n }\n\n /**\n * Log methods that are dynamically created based on current context and tag\n */\n get debug() {\n return this.createLogMethods().debug;\n }\n get log() {\n return this.createLogMethods().log;\n }\n get info() {\n return this.createLogMethods().info;\n }\n get warn() {\n return this.createLogMethods().warn;\n }\n get error() {\n return this.createLogMethods().error;\n }\n\n /**\n * Static helper to create a logger with a specific context\n */\n static forContext(context: string, tag?: string): Logger {\n const logger = new Logger(context);\n if (tag) {\n logger.setTag(tag);\n }\n return logger;\n }\n}\n", "import { AgentInfo } from \"porter-source\";\n\n/**\n * Formats an agent tag based on the agent information\n * @param agent Agent information\n * @param options Configuration options\n * @returns Formatted agent tag string\n */\nexport function getAgentTag(\n agent: AgentInfo,\n options: { terse?: boolean } = { terse: true }\n): string {\n const formatTabId = (tabId: number | string): string => {\n const tabIdStr = String(tabId);\n if (tabIdStr.length >= 4) {\n return tabIdStr.slice(-4);\n } else {\n return tabIdStr.padStart(4, \"0\");\n }\n };\n\n const formattedTabId = formatTabId(agent.location.tabId);\n\n if (options?.terse) {\n return `${formattedTabId}:${agent.location.frameId}`;\n }\n return `${agent.location.context}:${formattedTabId}:${agent.location.frameId}`;\n}\n", "import { createBasicEncoder } from \"./encoding\";\nimport type {\n MessageEndpoint,\n RemoteCallable,\n EncodingStrategy,\n EncodingStrategyApi,\n Retainer,\n CallMessage,\n ResultMessage,\n ErrorMessage,\n RPCMessage,\n} from \"./types\";\nimport { ActionsConfig } from \"../model/crann.model\";\nimport { Logger } from \"../utils/logger\";\nimport { getAgentTag } from \"../utils/agent\";\n\nconst CALL = 0;\nconst RESULT = 1;\nconst TERMINATE = 2;\nconst RELEASE = 3;\nconst FUNCTION_APPLY = 5;\nconst FUNCTION_RESULT = 6;\n\ntype AnyFunction = (...args: any[]) => any;\n\nexport interface CreateEndpointOptions<T = unknown> {\n uuid?(): string;\n createEncoder?(api: EncodingStrategyApi): EncodingStrategy;\n callable?: (keyof T)[];\n}\n\nexport interface Endpoint<T> {\n readonly call: RemoteCallable<T>;\n replace(messenger: MessageEndpoint): void;\n expose(api: Record<string, AnyFunction | undefined>): void;\n callable(...methods: string[]): void;\n terminate(): void;\n}\n\n/**\n * An endpoint wraps around a messenger, acting as the intermediary for all\n * messages both send from, and received by, that messenger. The endpoint sends\n * all messages as arrays, where the first element is the message type, and the\n * second is the arguments for that message (as an array). For messages that send\n * meaningful content across the wire (e.g., arguments to function calls, return\n * results), the endpoint first encodes these values.\n *\n * Encoding is done using a CBOR-like encoding scheme. The value is encoded into\n * an array buffer, and is paired with an additional array buffer that contains all\n * the strings used in that message (in the encoded value, strings are encoded as\n * their index in the \"strings\" encoding to reduce the cost of heavily-duplicated\n * strings, which is more likely in payloads containing UI). This encoding also takes\n * care of encoding functions: it uses a \"tagged\" item in CBOR to represent a\n * function as a string ID, which the opposite endpoint will be capable of turning\n * into a consistent, memory-manageable function proxy.\n *\n * The main CBOR encoding is entirely take from the [cbor.js package](https://github.com/paroga/cbor-js).\n * The special behavior for encoding strings and functions was then added in to the\n * encoder and decoder. For additional details on CBOR:\n *\n * @see https://tools.ietf.org/html/rfc7049\n */\nexport function createEndpoint<TState, TActions extends ActionsConfig<TState>>(\n messenger: MessageEndpoint,\n state: TState,\n actions: TActions,\n setState?: (newState: Partial<TState>) => Promise<void>,\n encodingStrategy?: EncodingStrategy\n): RemoteCallable<TActions> {\n const callbacks = new Map<number, (result: unknown) => void>();\n const retainedObjects = new Map<string, Set<Retainer>>();\n\n // Create logger - will be used in Service Worker or Agent context based on the messenger's context\n const contextPrefix = messenger.context?.isServiceWorker ? \"Core\" : \"Agent\";\n const logger = Logger.forContext(`${contextPrefix}:RPC`);\n\n // If we have agent info, set the tag\n if (messenger.context?.agentInfo) {\n logger.setTag(getAgentTag(messenger.context.agentInfo));\n }\n\n messenger.addEventListener(\"message\", (event) => {\n logger.debug(\"Message received:\", event);\n const [id, message] = event.data as [number, RPCMessage];\n\n if (\"call\" in message && \"args\" in message.call) {\n logger.debug(\"Processing call message:\", message);\n const callMessage = message.call;\n const { id: callId, args, target } = callMessage;\n const action = actions[callId];\n if (!action) {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: \"Action not found\", target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n return;\n }\n\n try {\n if (action.validate) {\n action.validate(...args);\n }\n\n // Ensure we have a target - if not provided, we need to handle this case\n if (!target) {\n messenger.postMessage([\n id,\n {\n error: {\n id: callId,\n error: \"No target provided for action call\",\n target,\n },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n return;\n }\n\n // Handle both synchronous and asynchronous results\n Promise.resolve(action.handler(state, setState!, target, ...args)).then(\n (result: unknown) => {\n logger.debug(\"Action handler result:\", {\n result,\n target,\n });\n messenger.postMessage([\n id,\n { result: { id: callId, result, target } },\n ] as [number, ResultMessage]);\n },\n (error: Error) => {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: error.message, target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n }\n );\n } catch (error) {\n if (error instanceof Error) {\n messenger.postMessage([\n id,\n { error: { id: callId, error: error.message, target } },\n ] as [number, ErrorMessage]);\n } else {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: \"Unknown error occurred\", target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n }\n }\n } else if (\"result\" in message) {\n const resultMessage = message.result;\n const callback = callbacks.get(id);\n if (callback) {\n callback(resultMessage.result);\n callbacks.delete(id);\n }\n } else if (\"error\" in message) {\n const errorMessage = message.error;\n const callback = callbacks.get(id);\n if (callback) {\n callback(Promise.reject(new Error(errorMessage.error)));\n callbacks.delete(id);\n }\n } else if (\"release\" in message) {\n const releaseMessage = message.release;\n const retainers = retainedObjects.get(releaseMessage.id);\n if (retainers) {\n retainers.clear();\n retainedObjects.delete(releaseMessage.id);\n }\n }\n });\n\n const proxy = new Proxy({} as RemoteCallable<TActions>, {\n get(_, prop: string) {\n return (...args: unknown[]) => {\n const id = Math.random();\n return new Promise((resolve, reject) => {\n callbacks.set(id, (result) => {\n if (result instanceof Promise) {\n result.then(resolve, reject);\n } else {\n resolve(result);\n }\n });\n messenger.postMessage([id, { call: { id: prop, args } }] as [\n number,\n CallMessage\n ]);\n });\n };\n },\n });\n\n return proxy;\n}\n\nfunction defaultUuid() {\n return `${uuidSegment()}-${uuidSegment()}-${uuidSegment()}-${uuidSegment()}`;\n}\n\nfunction uuidSegment() {\n return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16);\n}\n\nfunction createCallable<T>(\n handlerForCall: (\n property: string | number | symbol\n ) => AnyFunction | undefined,\n callable?: (keyof T)[]\n): RemoteCallable<T> {\n let call: any;\n\n if (callable == null) {\n if (typeof Proxy !== \"function\") {\n throw new Error(\n `You must pass an array of callable methods in environments without Proxies.`\n );\n }\n\n const cache = new Map<string | number | symbol, AnyFunction | undefined>();\n\n call = new Proxy(\n {},\n {\n get(_target, property) {\n if (cache.has(property)) {\n return cache.get(property);\n }\n\n const handler = handlerForCall(property);\n cache.set(property, handler);\n return handler;\n },\n }\n );\n } else {\n call = {};\n\n for (const method of callable) {\n Object.defineProperty(call, method, {\n value: handlerForCall(method),\n writable: false,\n configurable: true,\n enumerable: true,\n });\n }\n }\n\n return call;\n}\n", "import {\n ConfigItem,\n DerivedState,\n StateSubscriber,\n ConnectReturn,\n UseCrann,\n ConnectionStatus,\n StateChangeUpdate,\n ActionDefinition,\n AnyConfig,\n isStateItem,\n isActionItem,\n} from \"./model/crann.model\";\nimport { AgentInfo, connect as connectPorter } from \"porter-source\";\nimport { createCrannRPCAdapter } from \"./rpc/adapter\";\nimport { Logger } from \"./utils/logger\";\nimport { getAgentTag } from \"./utils/agent\";\n\nlet connectionStatus: ConnectionStatus = { connected: false };\nlet crannInstance: unknown = null;\n\nexport function connect<TConfig extends AnyConfig>(\n config: TConfig,\n options?: { context?: string; debug?: boolean }\n): ConnectReturn<TConfig> {\n const debug = options?.debug || false;\n const context = options?.context;\n\n // Set up logger\n if (debug) {\n Logger.setDebug(true);\n }\n const logger = Logger.forContext(\"Agent\");\n\n let _myInfo: AgentInfo;\n let _myTag = \"unset\";\n const readyCallbacks = new Set<(info: ConnectionStatus) => void>();\n\n logger.log(\n \"Initializing Crann Agent\" + (context ? ` with context: ${context}` : \"\")\n );\n if (crannInstance) {\n logger.log(\"We had an instance already, returning\");\n\n if (connectionStatus.connected) {\n logger.log(\"Connect, calling onReady callback\");\n setTimeout(() => {\n readyCallbacks.forEach((callback) => callback(connectionStatus));\n }, 0);\n }\n return crannInstance as ConnectReturn<TConfig>;\n }\n\n logger.log(\"No existing instance, creating a new one\");\n const porter = connectPorter({\n namespace: \"crann\",\n debug: false,\n });\n\n logger.log(\"Porter connection created\");\n\n // Initialize RPC with empty actions since this is the client side\n const actions = Object.entries(config)\n .filter(([_, value]) => isActionItem(value))\n .reduce<\n Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>\n >((acc, [key, value]) => {\n const action = value as ActionDefinition<\n DerivedState<TConfig>,\n any[],\n any\n >;\n return {\n ...acc,\n [key]: {\n type: \"action\",\n handler: action.handler,\n validate: action.validate,\n },\n };\n }, {});\n\n const rpcEndpoint = createCrannRPCAdapter(\n getDerivedState(config),\n actions,\n porter\n );\n\n let initialStateReceived = false;\n\n porter.on({\n initialState: (message) => {\n logger.log(\"initialState received\", {\n alreadyReceived: initialStateReceived,\n payload: message.payload,\n });\n\n if (initialStateReceived) {\n logger.log(\"Ignoring duplicate initialState message\");\n return;\n }\n\n initialStateReceived = true;\n\n _state = message.payload.state;\n _myInfo = message.payload.info;\n _myTag = getAgentTag(_myInfo);\n connectionStatus = { connected: true, agent: _myInfo };\n\n // Update logger with the agent tag once we have it\n logger.setTag(_myTag);\n logger.log(\n `Initial state received and ${listeners.size} listeners notified`,\n {\n message,\n }\n );\n readyCallbacks.forEach((callback) => {\n logger.log(\"Calling onReady callbacks\");\n callback(connectionStatus);\n });\n listeners.forEach((listener) => {\n listener.callback(_state);\n });\n },\n stateUpdate: (message) => {\n changes = message.payload.state;\n _state = { ..._state, ...changes };\n logger.log(\"State updated:\", { message, changes, _state });\n if (!changes) return;\n\n listeners.forEach((listener) => {\n if (listener.keys === undefined) {\n listener.callback(changes!);\n } else {\n const matchFound = listener.keys.some((key) => key in changes!);\n if (matchFound) {\n listener.callback(changes!);\n }\n }\n });\n },\n });\n logger.log(\"Porter connected. Setting up state and listeners\");\n let _state = getDerivedState(config);\n let changes: Partial<DerivedState<TConfig>> | null = null;\n const listeners = new Set<StateSubscriber<TConfig>>();\n\n logger.log(\"Completed setup, returning instance\");\n\n const get = () => _state;\n const set = (newState: Partial<DerivedState<TConfig>>) => {\n logger.log(\"Calling post with setState\", newState);\n porter.post({ action: \"setState\", payload: { state: newState } });\n };\n\n const subscribe = (\n callback: (changes: Partial<DerivedState<TConfig>>) => void,\n keys?: Array<keyof DerivedState<TConfig>>\n ): (() => void) => {\n const listener = { keys, callback };\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n };\n\n const useCrann: UseCrann<TConfig> = <K extends keyof DerivedState<TConfig>>(\n key: K\n ) => {\n const getValue = () => {\n const value = get()[key];\n return value as TConfig[K] extends ConfigItem<any>\n ? TConfig[K][\"default\"]\n : never;\n };\n\n const setValue = (\n value: TConfig[K] extends ConfigItem<any> ? TConfig[K][\"default\"] : never\n ) => set({ [key]: value } as Partial<DerivedState<TConfig>>);\n\n const subscribeToChanges = (\n callback: (update: StateChangeUpdate<TConfig, K>) => void\n ) => {\n let previousValue = getValue();\n\n return subscribe(\n (changes) => {\n if (key in changes) {\n const currentValue = getValue();\n const fullState = get();\n callback({\n current: currentValue,\n previous: previousValue,\n state: fullState,\n } as StateChangeUpdate<TConfig, K>);\n previousValue = currentValue;\n }\n },\n [key]\n );\n };\n\n return [getValue(), setValue, subscribeToChanges];\n };\n\n const onReady = (callback: (info: ConnectionStatus) => void) => {\n logger.log(\"onReady callback added\");\n readyCallbacks.add(callback);\n if (connectionStatus.connected) {\n logger.log(\"calling onReady callback\");\n setTimeout(() => {\n callback(connectionStatus);\n }, 0);\n }\n return () => readyCallbacks.delete(callback);\n };\n\n const getAgentInfo = () => _myInfo;\n\n const callAction = async (name: string, ...args: any[]) => {\n logger.log(\"Calling action\", name, args);\n return (rpcEndpoint as any)[name](...args);\n };\n\n const instance = {\n useCrann,\n get,\n set,\n subscribe,\n getAgentInfo,\n onReady,\n callAction,\n };\n\n crannInstance = instance;\n\n return crannInstance as ConnectReturn<TConfig>;\n}\n\nexport function connected(): boolean {\n return crannInstance !== null;\n}\n\nfunction getDerivedState<TConfig extends AnyConfig>(\n config: TConfig\n): DerivedState<TConfig> {\n const state: any = {};\n Object.keys(config).forEach((key) => {\n const item = config[key];\n if (isStateItem(item)) {\n state[key] = item.default;\n }\n });\n return state;\n}\n", "import { useState, useEffect, useCallback, useMemo, useRef } from \"react\";\nimport { ConfigItem, DerivedState, StateUpdate } from \"../model/crann.model\";\nimport { connect } from \"../crannAgent\";\n\nexport function createCrannStateHook<\n TConfig extends Record<string, ConfigItem<any>>\n>(config: TConfig) {\n return function useCrannState(context?: string) {\n const { useCrann, get, set, subscribe, callAction } = useMemo(() => {\n const instance = connect(config);\n return instance;\n }, [context]);\n\n const useStateItem = useCallback(\n <K extends keyof DerivedState<TConfig>>(key: K) => {\n const [value, setValue] = useState<DerivedState<TConfig>[K]>(\n get()[key]\n );\n const valueRef = useRef(value);\n\n useEffect(() => {\n valueRef.current = value;\n }, [value]);\n\n useEffect(() => {\n setValue(get()[key]);\n const unsubscribe = subscribe(\n (changes: StateUpdate<TConfig>) => {\n if (key in changes) {\n setValue(changes[key] as DerivedState<TConfig>[K]);\n }\n },\n [key]\n );\n return unsubscribe;\n }, [key]);\n\n const updateValue = useCallback(\n (newValue: DerivedState<TConfig>[K]) => {\n set({ [key]: newValue } as Partial<DerivedState<TConfig>>);\n },\n [key]\n );\n\n return [value, updateValue] as const;\n },\n [get, set, subscribe]\n );\n\n const getState = useCallback(() => get(), [get]);\n\n const setState = useCallback(\n (newState: Partial<DerivedState<TConfig>>) => {\n set(newState);\n },\n [set]\n );\n\n return {\n useStateItem,\n getState,\n setState,\n useCrann,\n callAction,\n };\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import browser from \"webextension-polyfill\";\nimport {\n DerivedInstanceState,\n DerivedServiceState,\n ConfigItem,\n DerivedState,\n Partition,\n CrannOptions,\n ActionDefinition,\n AnyConfig,\n isStateItem,\n isActionItem,\n} from \"./model/crann.model\";\nimport { AgentInfo, source, Agent } from \"porter-source\";\nimport { deepEqual } from \"./utils/deepEqual\";\nimport { BrowserLocation } from \"porter-source\";\nimport { trackStateChange } from \"./utils/tracking\";\nimport { DebugManager } from \"./utils/debug\";\nimport { createCrannRPCAdapter } from \"./rpc/adapter\";\nimport { Logger } from \"./utils/logger\";\nimport { getAgentTag } from \"./utils/agent\";\n\nexport class Crann<TConfig extends AnyConfig> {\n private static instance: Crann<any> | null = null;\n private instances: Map<string, DerivedInstanceState<TConfig>> = new Map();\n private defaultServiceState: DerivedServiceState<TConfig>;\n private defaultInstanceState: DerivedInstanceState<TConfig>;\n private serviceState: DerivedServiceState<TConfig>;\n private stateChangeListeners: Array<\n (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedServiceState<TConfig> & DerivedInstanceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n > = [];\n private instanceReadyListeners: Array<\n (instanceId: string, agent: AgentInfo) => void\n > = [];\n private storagePrefix = \"crann_\";\n private porter = source(\"crann\", { debug: false });\n private rpcEndpoint: ReturnType<typeof createCrannRPCAdapter>;\n private logger: Logger;\n\n constructor(private config: TConfig, options?: CrannOptions) {\n // Set the debug flag globally\n if (options?.debug) {\n DebugManager.setDebug(true);\n Logger.setDebug(true);\n }\n this.storagePrefix = options?.storagePrefix ?? this.storagePrefix;\n\n // Set up the core logger\n this.logger = Logger.forContext(\"Core\");\n this.logger.log(\"Constructing Crann with new logger\");\n\n // Hydrate the initial state from the config defaults and from storage\n this.defaultInstanceState = this.initializeInstanceDefault();\n this.defaultServiceState = this.serviceState =\n this.initializeServiceDefault();\n this.hydrate();\n\n // Set up the message handlers\n this.logger.log(\"Crann constructed, setting initial message handlers\");\n this.porter.on({\n setState: (message, info) => {\n if (!info) {\n this.logger.warn(\"setState message heard from unknown agent\");\n return;\n }\n\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Setting state:\", message);\n this.set(message.payload.state, info.id);\n },\n });\n\n // Track which agents we've already sent initialState to\n const agentsInitialized = new Set<string>();\n\n // Once the agents are connected and have set up their listeners, send them the initial state\n this.porter.onMessagesSet((info: AgentInfo) => {\n if (!info) {\n this.logger.error(\"Messages set but no agent info.\", { info });\n return;\n }\n\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"onMessagesSet received for agent:\", {\n id: info.id,\n context: info.location.context,\n tabId: info.location.tabId,\n frameId: info.location.frameId,\n alreadyInitialized: agentsInitialized.has(info.id),\n });\n\n // Skip sending initialState if we've already sent it to this agent\n if (agentsInitialized.has(info.id)) {\n this.logger\n .withTag(agentTag)\n .log(\"Already sent initialState to agent, skipping:\", info.id);\n return;\n }\n\n // Add the agent to the set of agents we've already sent initialState to\n agentsInitialized.add(info.id);\n\n this.logger\n .withTag(agentTag)\n .log(\"Messages set received. Sending initial state.\", { info });\n const fullState = this.get(info.id);\n this.porter.post(\n {\n action: \"initialState\",\n payload: { state: fullState, info },\n },\n info.location\n );\n\n this.notifyInstanceReady(info.id, info);\n });\n\n // Handle agent connection and disconnection\n this.porter.onConnect((info: AgentInfo) => {\n if (!info) {\n this.logger.error(\"Agent connected but no agent info.\", { info });\n return;\n }\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Agent connected\", { info });\n this.addInstance(info.id, agentTag);\n this.porter.onDisconnect((info: AgentInfo) => {\n this.logger\n .withTag(getAgentTag(info))\n .log(\n \"Agent disconnect heard. Connection type, context and location:\",\n { info }\n );\n this.removeInstance(info.id);\n });\n });\n\n // Initialize RPC with actions\n const actions = this.extractActions(config);\n this.rpcEndpoint = createCrannRPCAdapter(\n this.get(),\n actions,\n this.porter,\n (newState: Partial<DerivedState<TConfig>>) => this.set(newState)\n );\n }\n\n public static getInstance<TConfig extends AnyConfig>(\n config: TConfig,\n options?: CrannOptions\n ): Crann<TConfig> {\n if (!Crann.instance) {\n Crann.instance = new Crann(config, options);\n } else if (options?.debug) {\n const logger = Logger.forContext(\"Core\");\n logger.log(\"Instance requested and already existed, returning\");\n }\n return Crann.instance;\n }\n\n /**\n * Add an instance to the Crann instance.\n * @param key The key of the instance to add.\n * @param agentTag The tag of the agent that is adding the instance, for logging.\n */\n private async addInstance(key: string, agentTag: string): Promise<void> {\n if (!this.instances.has(key)) {\n this.logger.withTag(agentTag).log(\"Adding instance from agent key\");\n const initialInstanceState = {\n ...this.defaultInstanceState,\n } as DerivedInstanceState<TConfig>;\n this.instances.set(key, initialInstanceState);\n } else {\n this.logger\n .withTag(agentTag)\n .log(\"Instance was already registered, ignoring request from key\");\n }\n }\n\n private async removeInstance(key: string): Promise<void> {\n if (this.instances.has(key)) {\n this.logger.withTag(key).log(\"Remove instance requested\");\n this.instances.delete(key);\n } else {\n this.logger\n .withTag(key)\n .log(\"Remove instance requested but it did not exist!\");\n }\n }\n\n @trackStateChange\n public async setServiceState(\n state: Partial<DerivedServiceState<TConfig>>\n ): Promise<void> {\n this.logger.log(\"Request to set service state with:\", state);\n const update = { ...this.serviceState, ...state };\n if (!deepEqual(this.serviceState, update)) {\n this.logger.log(\n \"Confirmed new state was different than existing so proceeding to persist then notify all connected instances.\"\n );\n this.serviceState = update;\n await this.persist(state);\n this.notify(state as Partial<DerivedState<TConfig>>);\n } else {\n this.logger.log(\"New state seems to be the same as existing, skipping\");\n }\n }\n\n @trackStateChange\n public async setInstanceState(\n key: string,\n state: Partial<DerivedInstanceState<TConfig>>\n ): Promise<void> {\n this.logger\n .withTag(key)\n .log(\"Request to update instance state, update:\", state);\n const currentState = this.instances.get(key) || this.defaultInstanceState;\n const update = { ...currentState, ...state };\n if (!deepEqual(currentState, update)) {\n this.logger\n .withTag(key)\n .log(\"Instance state update is different, updating and notifying.\");\n this.instances.set(key, update);\n this.notify(state as Partial<DerivedState<TConfig>>, key);\n } else {\n this.logger\n .withTag(key)\n .log(\"Instance state update is not different, skipping update.\");\n }\n }\n\n // If we pass in specific state to persist, it only persists that state.\n // Otherwise persists all of the worker state.\n private async persist(\n state?: Partial<DerivedServiceState<TConfig>>\n ): Promise<void> {\n this.logger.log(\"Persisting state\");\n let wasPersisted = false;\n for (const key in state || this.serviceState) {\n const item = this.config[key] as ConfigItem<any>;\n const persistence = item.persist || \"none\";\n const value = state\n ? state[key as keyof DerivedServiceState<TConfig>]\n : this.serviceState[key];\n switch (persistence) {\n case \"session\":\n await browser.storage.session.set({\n [this.storagePrefix + (key as string)]: value,\n });\n wasPersisted = true;\n break;\n case \"local\":\n await browser.storage.local.set({\n [this.storagePrefix + (key as string)]: value,\n });\n wasPersisted = true;\n break;\n default:\n break;\n }\n }\n if (wasPersisted) {\n this.logger.log(\"State was persisted\");\n } else {\n this.logger.log(\"Nothing to persist\");\n }\n }\n\n public async clear(): Promise<void> {\n this.logger.log(\"Clearing state\");\n this.serviceState = this.defaultServiceState;\n this.instances.forEach((_, key) => {\n this.instances.set(key, this.defaultInstanceState);\n });\n await this.persist();\n this.notify({});\n }\n\n public subscribe(\n listener: (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n ): void {\n this.logger.log(\"Subscribing to state\");\n this.stateChangeListeners.push(listener);\n }\n\n // Right now we notify the instance even if the state change came from the instance.\n // This should probably be skipped for instance state, since it already knows.\n private notify(changes: Partial<DerivedState<TConfig>>, key?: string): void {\n const agent = key ? this.porter.getAgentById(key) : undefined;\n const state = key ? this.get(key) : this.get();\n\n if (this.stateChangeListeners.length > 0) {\n this.logger.log(\"Notifying state change listeners in source\");\n this.stateChangeListeners.forEach((listener) => {\n listener(state, changes, agent?.info);\n });\n }\n\n if (key && agent?.info.location) {\n this.logger.withTag(key).log(\"Notifying of state change.\");\n this.porter.post(\n { action: \"stateUpdate\", payload: { state: changes } },\n agent.info.location\n );\n } else {\n this.logger.log(\"Notifying everyone\");\n // for every key of this.instances, post the state update to the corresponding key\n this.instances.forEach((_, key) => {\n this.porter.post(\n { action: \"stateUpdate\", payload: { state: changes } },\n key\n );\n });\n }\n }\n\n public get(): DerivedState<TConfig>;\n public get(\n key: string\n ): DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>;\n public get(\n key?: string\n ): DerivedServiceState<TConfig> | DerivedState<TConfig> {\n if (!key) {\n return { ...this.serviceState, ...({} as DerivedInstanceState<TConfig>) };\n }\n return { ...this.serviceState, ...this.instances.get(key) };\n }\n\n // Todo: Should we return the instance data? What is the point of this.\n public findInstance(location: BrowserLocation): string | null {\n const agent = this.porter.getAgentByLocation(location);\n if (!agent) {\n this.logger.log(\"Could not find agent for location:\", { location });\n return null;\n }\n for (const [key, instance] of this.instances) {\n if (key === agent.info.id) {\n this.logger.log(\"Found instance for key:\", key);\n return key;\n }\n }\n this.logger.log(\"Could not find instance for context and location:\", {\n location,\n });\n return null;\n }\n\n // Convenience re-export of the porter-source queryAgents method.\n public queryAgents(query: Partial<BrowserLocation>): Agent[] {\n return this.porter.queryAgents(query);\n }\n\n public async set(state: Partial<DerivedServiceState<TConfig>>): Promise<void>;\n public async set(\n state: Partial<DerivedInstanceState<TConfig>>,\n key: string\n ): Promise<void>;\n public async set(\n state: Partial<DerivedState<TConfig>>,\n key?: string\n ): Promise<void> {\n const instance = {} as Partial<DerivedInstanceState<TConfig>>;\n const worker = {} as Partial<DerivedServiceState<TConfig>>;\n\n for (const itemKey in state) {\n const item = this.config[itemKey as keyof TConfig];\n if (isConfigItem(item)) {\n if (item.partition === \"instance\") {\n const instanceItemKey =\n itemKey as keyof DerivedInstanceState<TConfig>;\n const instanceState = state as Partial<DerivedInstanceState<TConfig>>;\n instance[instanceItemKey] = instanceState[instanceItemKey];\n } else if (!item.partition || item.partition === Partition.Service) {\n const serviceItemKey = itemKey as keyof DerivedServiceState<TConfig>;\n const serviceState = state as Partial<DerivedServiceState<TConfig>>;\n worker[serviceItemKey] = serviceState[serviceItemKey]!;\n }\n }\n }\n\n if (key && Object.keys(instance).length > 0) {\n this.logger.withTag(key).log(\"Setting instance state:\", instance);\n this.setInstanceState(key, instance);\n }\n if (Object.keys(worker).length > 0) {\n this.logger.log(\"Setting service state:\", worker);\n this.setServiceState(worker);\n }\n }\n\n private async hydrate(): Promise<void> {\n this.logger.log(\"Hydrating state from storage.\");\n const local = await browser.storage.local.get(null);\n const session = await browser.storage.session.get(null);\n const combined = { ...local, ...session };\n const update: Partial<DerivedServiceState<TConfig>> = {}; // Cast update as Partial<DerivedState<TConfig>>\n let hadItems = false;\n for (const prefixedKey in combined) {\n const key = this.removePrefix(prefixedKey);\n if (this.config.hasOwnProperty(key)) {\n const value = combined[key];\n update[key as keyof DerivedServiceState<TConfig>] = value;\n hadItems = true;\n }\n }\n if (hadItems) {\n this.logger.log(\"Hydrated some items.\");\n } else {\n this.logger.log(\"No items found in storage.\");\n }\n this.serviceState = { ...this.defaultServiceState, ...update };\n }\n\n private removePrefix(key: string): string {\n if (key.startsWith(this.storagePrefix)) {\n return key.replace(this.storagePrefix, \"\");\n }\n return key;\n }\n\n private initializeInstanceDefault(): DerivedInstanceState<TConfig> {\n const instanceState: any = {};\n Object.keys(this.config).forEach((key) => {\n const item = this.config[key];\n if (isStateItem(item) && item.partition === \"instance\") {\n instanceState[key] = item.default;\n }\n });\n return instanceState;\n }\n\n private initializeServiceDefault(): DerivedServiceState<TConfig> {\n const serviceState: any = {};\n Object.keys(this.config).forEach((key) => {\n const item = this.config[key];\n if (\n isStateItem(item) &&\n (!item.partition || item.partition === Partition.Service)\n ) {\n serviceState[key] = item.default;\n }\n });\n return serviceState;\n }\n\n public subscribeToInstanceReady(\n listener: (instanceId: string, agent: AgentInfo) => void\n ): () => void {\n this.logger.log(\"Subscribing to instance ready events\");\n this.instanceReadyListeners.push(listener);\n\n this.instances.forEach((_, instanceId) => {\n const agent = this.porter.getAgentById(instanceId);\n if (agent?.info) {\n listener(instanceId, agent.info);\n }\n });\n\n return () => {\n this.logger.log(\"Unsubscribing from instance ready events\");\n const index = this.instanceReadyListeners.indexOf(listener);\n if (index !== -1) {\n this.instanceReadyListeners.splice(index, 1);\n }\n };\n }\n\n private notifyInstanceReady(instanceId: string, info: AgentInfo): void {\n if (this.instanceReadyListeners.length > 0) {\n const agentTag = getAgentTag(info);\n this.logger.withTag(agentTag).log(\"Notifying instance ready listeners\");\n this.instanceReadyListeners.forEach((listener) => {\n listener(instanceId, info);\n });\n }\n }\n\n private extractActions(\n config: TConfig\n ): Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>> {\n return Object.entries(config)\n .filter(([_, value]) => isActionItem(value))\n .reduce<\n Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>\n >((acc, [key, value]) => {\n const action = value as ActionDefinition<\n DerivedState<TConfig>,\n any[],\n any\n >;\n return {\n ...acc,\n [key]: action,\n };\n }, {});\n }\n}\n\n// Define an interface for the API returned by create()\nexport interface CrannAPI<TConfig extends AnyConfig> {\n get: {\n (): DerivedState<TConfig>;\n (key: string): DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>;\n };\n set: {\n (state: Partial<DerivedServiceState<TConfig>>): Promise<void>;\n (\n state: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n key: string\n ): Promise<void>;\n };\n subscribe: (\n listener: (\n state: DerivedInstanceState<TConfig> | DerivedState<TConfig>,\n changes: Partial<\n DerivedInstanceState<TConfig> & DerivedServiceState<TConfig>\n >,\n agent?: AgentInfo\n ) => void\n ) => void;\n onInstanceReady: (\n listener: (instanceId: string, agent: AgentInfo) => void\n ) => () => void;\n findInstance: (location: BrowserLocation) => string | null;\n queryAgents: (query: Partial<BrowserLocation>) => Agent[];\n clear: () => Promise<void>;\n}\n\nexport function create<TConfig extends AnyConfig>(\n config: TConfig,\n options?: CrannOptions\n): CrannAPI<TConfig> {\n const instance = Crann.getInstance(config, options);\n\n return {\n get: instance.get.bind(instance),\n set: instance.set.bind(instance),\n subscribe: instance.subscribe.bind(instance),\n onInstanceReady: instance.subscribeToInstanceReady.bind(instance),\n findInstance: instance.findInstance.bind(instance),\n queryAgents: instance.queryAgents.bind(instance),\n clear: instance.clear.bind(instance),\n };\n}\n\nfunction isConfigItem(item: any): item is ConfigItem<any> {\n return item && typeof item === \"object\" && \"default\" in item;\n}\n", "import { AgentInfo, BrowserLocation } from \"porter-source\";\n\nexport const Partition = {\n Instance: \"instance\" as const,\n Service: \"service\" as const,\n};\n\nexport const Persistence = {\n Session: \"session\" as const,\n Local: \"local\" as const,\n None: \"none\" as const,\n};\n\nexport type ActionHandler<TState, TArgs extends any[], TResult> = (\n state: TState,\n setState: (newState: Partial<TState>) => Promise<void>,\n target: BrowserLocation,\n ...args: TArgs\n) => Promise<TResult>;\n\nexport type ActionDefinition<TState, TArgs extends any[], TResult> = {\n handler: ActionHandler<TState, TArgs, TResult>;\n validate?: (...args: TArgs) => void;\n};\n\nexport type ActionsConfig<TState> = {\n [K: string]: ActionDefinition<TState, any[], Partial<TState>>;\n};\n\n// Input types (what users provide in their config)\nexport type ConfigItem<T> = {\n default: T;\n partition?: (typeof Partition)[keyof typeof Partition];\n persist?: (typeof Persistence)[keyof typeof Persistence];\n};\n\nexport type AnyConfig = Record<\n string,\n ConfigItem<any> | ActionDefinition<any, any[], any>\n>;\n\n// Helper type to extract just the state items from a config\nexport type StateConfig<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> ? T[P] : never;\n};\n\n// Helper type to extract just the action items from a config\nexport type ActionConfig<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ActionDefinition<any, any[], any> ? T[P] : never;\n};\n\n// Update DerivedState to use the internal types\nexport type DerivedState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> ? T[P][\"default\"] : never;\n};\n\n// Update DerivedInstanceState to use the internal types\nexport type DerivedInstanceState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> & { partition: \"instance\" }\n ? T[P][\"default\"]\n : never;\n};\n\n// Update DerivedServiceState to use the internal types\nexport type DerivedServiceState<T extends AnyConfig> = {\n [P in keyof T]: T[P] extends ConfigItem<any> & { partition: \"service\" }\n ? T[P][\"default\"]\n : never;\n};\n\n// Type guards\nexport const isStateItem = <T>(\n item: ConfigItem<T> | ActionDefinition<any, any[], any>\n): item is ConfigItem<T> => {\n return !(\"handler\" in item);\n};\n\nexport const isActionItem = <TState, TArgs extends any[], TResult>(\n item: ConfigItem<any> | ActionDefinition<TState, TArgs, TResult>\n): item is ActionDefinition<TState, TArgs, TResult> => {\n return \"handler\" in item;\n};\n\ntype StateSubscriber<TConfig extends AnyConfig> = {\n keys?: Array<keyof DerivedState<TConfig>>;\n callback: (changes: StateUpdate<TConfig>) => void;\n};\n\ntype CrannAgent<TConfig extends AnyConfig> = {\n get: () => DerivedState<TConfig>;\n set: (update: StateUpdate<TConfig>) => void;\n subscribe: (\n callback: (changes: StateUpdate<TConfig>) => void,\n keys?: Array<keyof TConfig>\n ) => () => void;\n getAgentInfo: () => AgentInfo;\n onReady: (callback: (info: ConnectionStatus) => void) => () => void;\n};\n\ntype UseCrann<TConfig extends AnyConfig> = <\n K extends keyof DerivedState<TConfig>\n>(\n key: K\n) => [\n DerivedState<TConfig>[K],\n (value: DerivedState<TConfig>[K]) => void,\n (callback: (update: StateChangeUpdate<TConfig, K>) => void) => () => void\n];\n\ntype ConnectReturn<TConfig extends AnyConfig> = {\n useCrann: UseCrann<TConfig>;\n get: CrannAgent<TConfig>[\"get\"];\n set: CrannAgent<TConfig>[\"set\"];\n subscribe: CrannAgent<TConfig>[\"subscribe\"];\n getAgentInfo: CrannAgent<TConfig>[\"getAgentInfo\"];\n onReady: CrannAgent<TConfig>[\"onReady\"];\n callAction: (name: string, ...args: any[]) => Promise<any>;\n};\n\ntype StateChangeUpdate<\n TConfig extends AnyConfig,\n K extends keyof DerivedState<TConfig>\n> = {\n current: DerivedState<TConfig>[K];\n previous: DerivedState<TConfig>[K];\n state: DerivedState<TConfig>;\n};\n\ntype AgentSubscription<TConfig extends AnyConfig> = {\n (\n callback: (changes: StateUpdate<TConfig>) => void,\n key?: keyof DerivedState<TConfig>\n ): number;\n};\n\ntype StateUpdate<TConfig extends AnyConfig> = Partial<DerivedState<TConfig>>;\n\nexport type CrannOptions = {\n debug?: boolean;\n storagePrefix?: string;\n};\n\ntype ConnectionStatus = {\n connected: boolean;\n agent?: AgentInfo;\n};\n\nexport type CrannConfig<TState> = {\n [K: string]: ConfigItem<any> | ActionsConfig<TState>;\n};\n\nexport {\n StateSubscriber,\n CrannAgent,\n AgentSubscription,\n StateUpdate,\n DerivedState as State,\n ConnectReturn,\n UseCrann,\n ConnectionStatus,\n StateChangeUpdate,\n};\n", "export function deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n\n if (a == null || typeof a !== 'object' || b == null || typeof b !== 'object') return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n keysA.sort();\n keysB.sort();\n\n for (let i = 0; i < keysA.length; i++) {\n const key = keysA[i];\n if (key !== keysB[i] || !deepEqual(a[key], b[key])) return false;\n }\n return true;\n}", "// Create a global debug state manager\nexport class DebugManager {\n private static _debug: boolean = false;\n\n static setDebug(value: boolean): void {\n DebugManager._debug = value;\n }\n\n static isDebugEnabled(): boolean {\n return DebugManager._debug;\n }\n}\n\n// Export a convenience function\nexport function isDebugEnabled(): boolean {\n return DebugManager.isDebugEnabled();\n}\n", "import { isDebugEnabled } from \"./debug\";\n\nexport type StateChangeMetadata = {\n source: string;\n timestamp: number;\n changes: any;\n instanceKey?: string;\n};\n\nexport function trackStateChange(\n target: any,\n propertyKey: string,\n descriptor: PropertyDescriptor\n): PropertyDescriptor {\n const originalMethod = descriptor.value;\n\n descriptor.value = function (...args: any[]) {\n // Only log if debugging is enabled\n if (isDebugEnabled()) {\n // Get the stack trace to find the actual caller\n const stack = new Error().stack;\n const lines = stack?.split(\"\\n\") || [];\n const callerMatch = lines[3]?.match(/at\\s+(\\S+)\\s+/);\n const caller = callerMatch ? callerMatch[1] : \"unknown\";\n\n const changes = args.length > 1 ? args[1] : undefined;\n\n const metadata: StateChangeMetadata = {\n source: caller,\n timestamp: Date.now(),\n instanceKey: args[0],\n changes,\n };\n\n console.log(`Crann State Change:`, metadata);\n }\n return originalMethod.apply(this, args);\n };\n\n return descriptor;\n}\n", "import { source, AgentInfo, connect, Message, AgentAPI } from \"porter-source\";\nimport { createEndpoint } from \"./endpoint\";\nimport { MessageEndpoint, CallMessage, RPCMessage } from \"./types\";\nimport { ActionsConfig } from \"../model/crann.model\";\nimport { Logger } from \"../utils/logger\";\nimport { getAgentTag } from \"../utils/agent\";\n\nexport function createCrannRPCAdapter<\n TState,\n TActions extends ActionsConfig<TState>\n>(\n initialState: TState,\n actions: TActions,\n porter?: ReturnType<typeof source> | ReturnType<typeof connect>,\n setState?: (newState: Partial<TState>) => Promise<void>\n) {\n const porterInstance = porter || source(\"crann\");\n\n // Determine if this is a service worker instance (source) or content script instance (connect)\n const isServiceWorker = !(porterInstance.type === \"agent\");\n\n // Set up logger with the appropriate context\n const logger = Logger.forContext(isServiceWorker ? \"Core:RPC\" : \"Agent:RPC\");\n\n const messageEndpoint: MessageEndpoint = {\n postMessage: (message, transferables) => {\n if (isServiceWorker) {\n logger.debug(\"Posting message from service worker:\", {\n message,\n transferables,\n });\n // In service worker, we need to respond to the specific target\n const [, rpcPayload] = message;\n const target = getTargetFromMessage(rpcPayload);\n if (!target) {\n logger.warn(\"No target specified for RPC response in service worker\");\n return;\n }\n porterInstance.post(\n {\n action: \"rpc\",\n payload: {\n message,\n transferables: transferables || [],\n },\n },\n target\n );\n } else {\n // In content script (agent) context\n // Get the agent info only when needed\n const agentInfo = (porterInstance as AgentAPI).getAgentInfo();\n\n if (!agentInfo) {\n logger.warn(\"No agent info found for posting message\", { agentInfo });\n return;\n }\n\n // Get the agent tag for logging\n const myTag = getAgentTag(agentInfo);\n\n // Destructure the tuple, skipping the messageId which we don't need\n const [, rpcPayload] = message;\n\n // Use type guard to check if it's a call message\n if (\"call\" in rpcPayload) {\n // Add the target info to the call message\n rpcPayload.call.target = agentInfo?.location;\n }\n\n logger.withTag(myTag).debug(\"Sending RPC message from agent:\", {\n rpcPayload,\n message,\n });\n // In content script, target is automatically the service worker\n porterInstance.post({\n action: \"rpc\",\n payload: {\n message,\n transferables: transferables || [],\n },\n });\n }\n },\n addEventListener: (event, listener) => {\n porterInstance.on({\n rpc: (message: Message<string>, info?: AgentInfo) => {\n try {\n if (!info) {\n logger.debug(\"RPC message received:\", {\n message,\n event,\n });\n } else {\n // Get the agent tag for logging\n const myTag = getAgentTag(info);\n logger.withTag(myTag).debug(\"RPC message received:\", {\n message,\n event,\n });\n }\n\n const { payload } = message;\n const { message: originalMessage, transferables = [] } = payload;\n const rpcEvent = new MessageEvent(\"message\", {\n data: originalMessage,\n ports:\n (transferables.filter(\n (t: unknown) => t instanceof MessagePort\n ) as MessagePort[]) || [],\n });\n listener(rpcEvent);\n } catch (e) {\n logger.error(\"Failed to parse RPC message payload:\", e);\n }\n },\n });\n },\n removeEventListener: () => {\n // Porter-source doesn't support removing listeners\n },\n // Add context information\n context: {\n isServiceWorker,\n agentInfo: !isServiceWorker\n ? (porterInstance as AgentAPI).getAgentInfo()\n : undefined,\n },\n };\n\n return createEndpoint(messageEndpoint, initialState, actions, setState);\n}\n\n// Don't love this being here. Let's move it sometime soon,\n// or find another way to do this.\nfunction getTargetFromMessage(payload: RPCMessage): any {\n if (\"result\" in payload) return payload.result.target;\n if (\"error\" in payload) return payload.error.target;\n if (\"call\" in payload) return payload.call.target;\n if (\"release\" in payload) return payload.release.target;\n return undefined;\n}\n", "export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport class Logger {\n private static debug = false;\n private static prefix = \"CrannLogger\";\n private static noOp = function () {};\n\n private context: string;\n private tag: string | null = null;\n\n /**\n * Create a new Logger instance with a specific context\n */\n constructor(context: string) {\n this.context = context;\n }\n\n static setDebug(value: boolean): void {\n Logger.debug = value;\n }\n\n static setPrefix(value: string): void {\n Logger.prefix = value;\n }\n\n /**\n * Set a persistent tag for this Logger instance\n */\n setTag(tag: string | null): void {\n this.tag = tag;\n }\n\n /**\n * Create a temporary logger with a specific tag\n * This doesn't modify the original logger instance\n */\n withTag(tag: string) {\n const tempLogger = new Logger(this.context);\n tempLogger.setTag(tag);\n return tempLogger;\n }\n\n /**\n * Get the full context string including tag if present\n */\n private getFullContext(): string {\n if (this.tag) {\n return `${this.context}:${this.tag}`;\n }\n return this.context;\n }\n\n /**\n * Create the log methods bound to the current context and tag\n */\n private createLogMethods() {\n const fullContext = this.getFullContext();\n const formatString = `%c${Logger.prefix}%c [%c${fullContext}%c]`;\n\n // Styles for the prefix and context - updated for better readability on dark backgrounds\n const prefixStyle = \"color: #3fcbff; font-weight: bold\"; // Bright cyan\n const contextStyle = \"color: #d58cff; font-weight: bold\"; // Bright purple\n const resetStyle = \"\";\n\n if (Logger.debug) {\n return {\n debug: console.log.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n log: console.log.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n info: console.info.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n warn: console.warn.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n error: console.error.bind(\n console,\n formatString,\n prefixStyle,\n resetStyle,\n contextStyle,\n resetStyle\n ),\n };\n } else {\n return {\n debug: Logger.noOp,\n log: Logger.noOp,\n info: Logger.noOp,\n warn: Logger.noOp,\n error: Logger.noOp,\n };\n }\n }\n\n /**\n * Log methods that are dynamically created based on current context and tag\n */\n get debug() {\n return this.createLogMethods().debug;\n }\n get log() {\n return this.createLogMethods().log;\n }\n get info() {\n return this.createLogMethods().info;\n }\n get warn() {\n return this.createLogMethods().warn;\n }\n get error() {\n return this.createLogMethods().error;\n }\n\n /**\n * Static helper to create a logger with a specific context\n */\n static forContext(context: string, tag?: string): Logger {\n const logger = new Logger(context);\n if (tag) {\n logger.setTag(tag);\n }\n return logger;\n }\n}\n", "import { AgentInfo } from \"porter-source\";\n\n/**\n * Formats an agent tag based on the agent information\n * @param agent Agent information\n * @param options Configuration options\n * @returns Formatted agent tag string\n */\nexport function getAgentTag(\n agent: AgentInfo,\n options: { terse?: boolean } = { terse: true }\n): string {\n const formatTabId = (tabId: number | string): string => {\n const tabIdStr = String(tabId);\n if (tabIdStr.length >= 4) {\n return tabIdStr.slice(-4);\n } else {\n return tabIdStr.padStart(4, \"0\");\n }\n };\n\n const formattedTabId = formatTabId(agent.location.tabId);\n\n if (options?.terse) {\n return `${formattedTabId}:${agent.location.frameId}`;\n }\n return `${agent.location.context}:${formattedTabId}:${agent.location.frameId}`;\n}\n", "import { createBasicEncoder } from \"./encoding\";\nimport type {\n MessageEndpoint,\n RemoteCallable,\n EncodingStrategy,\n EncodingStrategyApi,\n Retainer,\n CallMessage,\n ResultMessage,\n ErrorMessage,\n RPCMessage,\n} from \"./types\";\nimport { ActionsConfig } from \"../model/crann.model\";\nimport { Logger } from \"../utils/logger\";\nimport { getAgentTag } from \"../utils/agent\";\n\nconst CALL = 0;\nconst RESULT = 1;\nconst TERMINATE = 2;\nconst RELEASE = 3;\nconst FUNCTION_APPLY = 5;\nconst FUNCTION_RESULT = 6;\n\ntype AnyFunction = (...args: any[]) => any;\n\nexport interface CreateEndpointOptions<T = unknown> {\n uuid?(): string;\n createEncoder?(api: EncodingStrategyApi): EncodingStrategy;\n callable?: (keyof T)[];\n}\n\nexport interface Endpoint<T> {\n readonly call: RemoteCallable<T>;\n replace(messenger: MessageEndpoint): void;\n expose(api: Record<string, AnyFunction | undefined>): void;\n callable(...methods: string[]): void;\n terminate(): void;\n}\n\n/**\n * An endpoint wraps around a messenger, acting as the intermediary for all\n * messages both send from, and received by, that messenger. The endpoint sends\n * all messages as arrays, where the first element is the message type, and the\n * second is the arguments for that message (as an array). For messages that send\n * meaningful content across the wire (e.g., arguments to function calls, return\n * results), the endpoint first encodes these values.\n *\n * Encoding is done using a CBOR-like encoding scheme. The value is encoded into\n * an array buffer, and is paired with an additional array buffer that contains all\n * the strings used in that message (in the encoded value, strings are encoded as\n * their index in the \"strings\" encoding to reduce the cost of heavily-duplicated\n * strings, which is more likely in payloads containing UI). This encoding also takes\n * care of encoding functions: it uses a \"tagged\" item in CBOR to represent a\n * function as a string ID, which the opposite endpoint will be capable of turning\n * into a consistent, memory-manageable function proxy.\n *\n * The main CBOR encoding is entirely take from the [cbor.js package](https://github.com/paroga/cbor-js).\n * The special behavior for encoding strings and functions was then added in to the\n * encoder and decoder. For additional details on CBOR:\n *\n * @see https://tools.ietf.org/html/rfc7049\n */\nexport function createEndpoint<TState, TActions extends ActionsConfig<TState>>(\n messenger: MessageEndpoint,\n state: TState,\n actions: TActions,\n setState?: (newState: Partial<TState>) => Promise<void>,\n encodingStrategy?: EncodingStrategy\n): RemoteCallable<TActions> {\n const callbacks = new Map<number, (result: unknown) => void>();\n const retainedObjects = new Map<string, Set<Retainer>>();\n\n // Create logger - will be used in Service Worker or Agent context based on the messenger's context\n const contextPrefix = messenger.context?.isServiceWorker ? \"Core\" : \"Agent\";\n const logger = Logger.forContext(`${contextPrefix}:RPC`);\n\n // If we have agent info, set the tag\n if (messenger.context?.agentInfo) {\n logger.setTag(getAgentTag(messenger.context.agentInfo));\n }\n\n messenger.addEventListener(\"message\", (event) => {\n logger.debug(\"Message received:\", event);\n const [id, message] = event.data as [number, RPCMessage];\n\n if (\"call\" in message && \"args\" in message.call) {\n logger.debug(\"Processing call message:\", message);\n const callMessage = message.call;\n const { id: callId, args, target } = callMessage;\n const action = actions[callId];\n if (!action) {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: \"Action not found\", target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n return;\n }\n\n try {\n if (action.validate) {\n action.validate(...args);\n }\n\n // Ensure we have a target - if not provided, we need to handle this case\n if (!target) {\n messenger.postMessage([\n id,\n {\n error: {\n id: callId,\n error: \"No target provided for action call\",\n target,\n },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n return;\n }\n\n // Handle both synchronous and asynchronous results\n Promise.resolve(action.handler(state, setState!, target, ...args)).then(\n (result: unknown) => {\n logger.debug(\"Action handler result:\", {\n result,\n target,\n });\n messenger.postMessage([\n id,\n { result: { id: callId, result, target } },\n ] as [number, ResultMessage]);\n },\n (error: Error) => {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: error.message, target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n }\n );\n } catch (error) {\n if (error instanceof Error) {\n messenger.postMessage([\n id,\n { error: { id: callId, error: error.message, target } },\n ] as [number, ErrorMessage]);\n } else {\n messenger.postMessage([\n id,\n {\n error: { id: callId, error: \"Unknown error occurred\", target },\n } as ErrorMessage,\n ] as [number, ErrorMessage]);\n }\n }\n } else if (\"result\" in message) {\n const resultMessage = message.result;\n const callback = callbacks.get(id);\n if (callback) {\n callback(resultMessage.result);\n callbacks.delete(id);\n }\n } else if (\"error\" in message) {\n const errorMessage = message.error;\n const callback = callbacks.get(id);\n if (callback) {\n callback(Promise.reject(new Error(errorMessage.error)));\n callbacks.delete(id);\n }\n } else if (\"release\" in message) {\n const releaseMessage = message.release;\n const retainers = retainedObjects.get(releaseMessage.id);\n if (retainers) {\n retainers.clear();\n retainedObjects.delete(releaseMessage.id);\n }\n }\n });\n\n const proxy = new Proxy({} as RemoteCallable<TActions>, {\n get(_, prop: string) {\n return (...args: unknown[]) => {\n const id = Math.random();\n return new Promise((resolve, reject) => {\n callbacks.set(id, (result) => {\n if (result instanceof Promise) {\n result.then(resolve, reject);\n } else {\n resolve(result);\n }\n });\n messenger.postMessage([id, { call: { id: prop, args } }] as [\n number,\n CallMessage\n ]);\n });\n };\n },\n });\n\n return proxy;\n}\n\nfunction defaultUuid() {\n return `${uuidSegment()}-${uuidSegment()}-${uuidSegment()}-${uuidSegment()}`;\n}\n\nfunction uuidSegment() {\n return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16);\n}\n\nfunction createCallable<T>(\n handlerForCall: (\n property: string | number | symbol\n ) => AnyFunction | undefined,\n callable?: (keyof T)[]\n): RemoteCallable<T> {\n let call: any;\n\n if (callable == null) {\n if (typeof Proxy !== \"function\") {\n throw new Error(\n `You must pass an array of callable methods in environments without Proxies.`\n );\n }\n\n const cache = new Map<string | number | symbol, AnyFunction | undefined>();\n\n call = new Proxy(\n {},\n {\n get(_target, property) {\n if (cache.has(property)) {\n return cache.get(property);\n }\n\n const handler = handlerForCall(property);\n cache.set(property, handler);\n return handler;\n },\n }\n );\n } else {\n call = {};\n\n for (const method of callable) {\n Object.defineProperty(call, method, {\n value: handlerForCall(method),\n writable: false,\n configurable: true,\n enumerable: true,\n });\n }\n }\n\n return call;\n}\n", "import {\n ConfigItem,\n DerivedState,\n StateSubscriber,\n ConnectReturn,\n UseCrann,\n ConnectionStatus,\n StateChangeUpdate,\n ActionDefinition,\n AnyConfig,\n isStateItem,\n isActionItem,\n} from \"./model/crann.model\";\nimport { AgentInfo, connect as connectPorter } from \"porter-source\";\nimport { createCrannRPCAdapter } from \"./rpc/adapter\";\nimport { Logger } from \"./utils/logger\";\nimport { getAgentTag } from \"./utils/agent\";\n\nlet connectionStatus: ConnectionStatus = { connected: false };\nlet crannInstance: unknown = null;\n\nexport function connect<TConfig extends AnyConfig>(\n config: TConfig,\n options?: { context?: string; debug?: boolean }\n): ConnectReturn<TConfig> {\n const debug = options?.debug || false;\n const context = options?.context;\n\n // Set up logger\n if (debug) {\n Logger.setDebug(true);\n }\n const logger = Logger.forContext(\"Agent\");\n\n let _myInfo: AgentInfo;\n let _myTag = \"unset\";\n const readyCallbacks = new Set<(info: ConnectionStatus) => void>();\n\n logger.log(\n \"Initializing Crann Agent\" + (context ? ` with context: ${context}` : \"\")\n );\n if (crannInstance) {\n logger.log(\"We had an instance already, returning\");\n\n if (connectionStatus.connected) {\n logger.log(\"Connect, calling onReady callback\");\n setTimeout(() => {\n readyCallbacks.forEach((callback) => callback(connectionStatus));\n }, 0);\n }\n return crannInstance as ConnectReturn<TConfig>;\n }\n\n logger.log(\"No existing instance, creating a new one\");\n const porter = connectPorter({\n namespace: \"crann\",\n debug: false,\n });\n\n logger.log(\"Porter connection created\");\n\n // Initialize RPC with empty actions since this is the client side\n const actions = Object.entries(config)\n .filter(([_, value]) => isActionItem(value))\n .reduce<\n Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>\n >((acc, [key, value]) => {\n const action = value as ActionDefinition<\n DerivedState<TConfig>,\n any[],\n any\n >;\n return {\n ...acc,\n [key]: {\n type: \"action\",\n handler: action.handler,\n validate: action.validate,\n },\n };\n }, {});\n\n const rpcEndpoint = createCrannRPCAdapter(\n getDerivedState(config),\n actions,\n porter\n );\n\n let initialStateReceived = false;\n\n porter.on({\n initialState: (message) => {\n logger.log(\"initialState received\", {\n alreadyReceived: initialStateReceived,\n payload: message.payload,\n });\n\n if (initialStateReceived) {\n logger.log(\"Ignoring duplicate initialState message\");\n return;\n }\n\n initialStateReceived = true;\n\n _state = message.payload.state;\n _myInfo = message.payload.info;\n _myTag = getAgentTag(_myInfo);\n connectionStatus = { connected: true, agent: _myInfo };\n\n // Update logger with the agent tag once we have it\n logger.setTag(_myTag);\n logger.log(\n `Initial state received and ${listeners.size} listeners notified`,\n {\n message,\n }\n );\n readyCallbacks.forEach((callback) => {\n logger.log(\"Calling onReady callbacks\");\n callback(connectionStatus);\n });\n listeners.forEach((listener) => {\n listener.callback(_state);\n });\n },\n stateUpdate: (message) => {\n changes = message.payload.state;\n _state = { ..._state, ...changes };\n logger.log(\"State updated:\", { message, changes, _state });\n if (!changes) return;\n\n listeners.forEach((listener) => {\n if (listener.keys === undefined) {\n listener.callback(changes!);\n } else {\n const matchFound = listener.keys.some((key) => key in changes!);\n if (matchFound) {\n listener.callback(changes!);\n }\n }\n });\n },\n });\n logger.log(\"Porter connected. Setting up state and listeners\");\n let _state = getDerivedState(config);\n let changes: Partial<DerivedState<TConfig>> | null = null;\n const listeners = new Set<StateSubscriber<TConfig>>();\n\n logger.log(\"Completed setup, returning instance\");\n\n const get = () => _state;\n const set = (newState: Partial<DerivedState<TConfig>>) => {\n logger.log(\"Calling post with setState\", newState);\n porter.post({ action: \"setState\", payload: { state: newState } });\n };\n\n const subscribe = (\n callback: (changes: Partial<DerivedState<TConfig>>) => void,\n keys?: Array<keyof DerivedState<TConfig>>\n ): (() => void) => {\n const listener = { keys, callback };\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n };\n\n const useCrann: UseCrann<TConfig> = <K extends keyof DerivedState<TConfig>>(\n key: K\n ) => {\n const getValue = () => {\n const value = get()[key];\n return value as TConfig[K] extends ConfigItem<any>\n ? TConfig[K][\"default\"]\n : never;\n };\n\n const setValue = (\n value: TConfig[K] extends ConfigItem<any> ? TConfig[K][\"default\"] : never\n ) => set({ [key]: value } as Partial<DerivedState<TConfig>>);\n\n const subscribeToChanges = (\n callback: (update: StateChangeUpdate<TConfig, K>) => void\n ) => {\n let previousValue = getValue();\n\n return subscribe(\n (changes) => {\n if (key in changes) {\n const currentValue = getValue();\n const fullState = get();\n callback({\n current: currentValue,\n previous: previousValue,\n state: fullState,\n } as StateChangeUpdate<TConfig, K>);\n previousValue = currentValue;\n }\n },\n [key]\n );\n };\n\n return [getValue(), setValue, subscribeToChanges];\n };\n\n const onReady = (callback: (info: ConnectionStatus) => void) => {\n logger.log(\"onReady callback added\");\n readyCallbacks.add(callback);\n if (connectionStatus.connected) {\n logger.log(\"calling onReady callback\");\n setTimeout(() => {\n callback(connectionStatus);\n }, 0);\n }\n return () => readyCallbacks.delete(callback);\n };\n\n const getAgentInfo = () => _myInfo;\n\n const callAction = async (name: string, ...args: any[]) => {\n logger.log(\"Calling action\", name, args);\n return (rpcEndpoint as any)[name](...args);\n };\n\n const instance = {\n useCrann,\n get,\n set,\n subscribe,\n getAgentInfo,\n onReady,\n callAction,\n };\n\n crannInstance = instance;\n\n return crannInstance as ConnectReturn<TConfig>;\n}\n\nexport function connected(): boolean {\n return crannInstance !== null;\n}\n\nfunction getDerivedState<TConfig extends AnyConfig>(\n config: TConfig\n): DerivedState<TConfig> {\n const state: any = {};\n Object.keys(config).forEach((key) => {\n const item = config[key];\n if (isStateItem(item)) {\n state[key] = item.default;\n }\n });\n return state;\n}\n", "import { useState, useEffect, useCallback, useMemo, useRef } from \"react\";\nimport {\n AnyConfig,\n ConfigItem,\n DerivedState,\n StateUpdate,\n} from \"../model/crann.model\";\nimport { connect } from \"../crannAgent\";\n\nexport function createCrannStateHook<TConfig extends AnyConfig>(\n config: TConfig\n) {\n return function useCrannState(context?: string) {\n const { useCrann, get, set, subscribe, callAction } = useMemo(() => {\n const instance = connect(config);\n return instance;\n }, [context]);\n\n const useStateItem = useCallback(\n <K extends keyof DerivedState<TConfig>>(key: K) => {\n const [value, setValue] = useState<DerivedState<TConfig>[K]>(\n get()[key]\n );\n const valueRef = useRef(value);\n\n useEffect(() => {\n valueRef.current = value;\n }, [value]);\n\n useEffect(() => {\n setValue(get()[key]);\n const unsubscribe = subscribe(\n (changes: StateUpdate<TConfig>) => {\n if (key in changes) {\n setValue(changes[key] as DerivedState<TConfig>[K]);\n }\n },\n [key]\n );\n return unsubscribe;\n }, [key]);\n\n const updateValue = useCallback(\n (newValue: DerivedState<TConfig>[K]) => {\n set({ [key]: newValue } as Partial<DerivedState<TConfig>>);\n },\n [key]\n );\n\n return [value, updateValue] as const;\n },\n [get, set, subscribe]\n );\n\n const getState = useCallback(() => get(), [get]);\n\n const setState = useCallback(\n (newState: Partial<DerivedState<TConfig>>) => {\n set(newState);\n },\n [set]\n );\n\n return {\n useStateItem,\n getState,\n setState,\n useCrann,\n callAction,\n };\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["browser", "Partition", "Persistence", "isStateItem", "item", "isActionItem", "source", "deepEqual", "a", "b", "keysA", "keysB", "key", "_DebugManager", "value", "DebugManager", "isDebugEnabled", "trackStateChange", "target", "propertyKey", "descriptor", "originalMethod", "args", "_a", "isDebugEnabled", "stack", "callerMatch", "caller", "changes", "metadata", "source", "_Logger", "context", "value", "tag", "tempLogger", "fullContext", "formatString", "prefixStyle", "contextStyle", "resetStyle", "logger", "Logger", "getAgentTag", "agent", "options", "formattedTabId", "tabId", "tabIdStr", "createEndpoint", "messenger", "state", "actions", "setState", "encodingStrategy", "_a", "_b", "callbacks", "retainedObjects", "contextPrefix", "logger", "Logger", "getAgentTag", "event", "id", "message", "callMessage", "callId", "args", "target", "action", "result", "error", "resultMessage", "callback", "errorMessage", "releaseMessage", "retainers", "_", "prop", "resolve", "reject", "createCrannRPCAdapter", "initialState", "actions", "porter", "setState", "porterInstance", "source", "isServiceWorker", "logger", "Logger", "messageEndpoint", "message", "transferables", "rpcPayload", "target", "getTargetFromMessage", "agentInfo", "myTag", "getAgentTag", "event", "listener", "info", "payload", "originalMessage", "rpcEvent", "t", "e", "createEndpoint", "_Crann", "config", "options", "source", "_a", "DebugManager", "Logger", "message", "info", "agentTag", "getAgentTag", "agentsInitialized", "fullState", "actions", "createCrannRPCAdapter", "newState", "key", "initialInstanceState", "state", "update", "deepEqual", "currentState", "wasPersisted", "persistence", "value", "browser", "_", "listener", "changes", "agent", "location", "instance", "query", "worker", "itemKey", "item", "isConfigItem", "instanceItemKey", "instanceState", "Partition", "serviceItemKey", "serviceState", "local", "session", "combined", "hadItems", "prefixedKey", "isStateItem", "instanceId", "index", "isActionItem", "acc", "action", "__decorateClass", "trackStateChange", "Crann", "create", "connectPorter", "connectionStatus", "crannInstance", "connect", "config", "options", "debug", "context", "Logger", "logger", "_myInfo", "_myTag", "readyCallbacks", "callback", "porter", "connectPorter", "actions", "_", "value", "isActionItem", "acc", "key", "action", "rpcEndpoint", "createCrannRPCAdapter", "getDerivedState", "initialStateReceived", "message", "_state", "getAgentTag", "listeners", "listener", "changes", "get", "set", "newState", "subscribe", "keys", "getValue", "setValue", "subscribeToChanges", "previousValue", "currentValue", "fullState", "name", "args", "connected", "state", "item", "isStateItem", "useState", "useEffect", "useCallback", "useMemo", "useRef", "createCrannStateHook", "config", "context", "useCrann", "get", "set", "subscribe", "callAction", "useMemo", "connect", "useStateItem", "useCallback", "key", "value", "setValue", "useState", "valueRef", "useRef", "useEffect", "changes", "updateValue", "newValue", "getState", "setState", "newState"]
7
7
  }
@@ -1,5 +1,5 @@
1
- import { ConfigItem, DerivedState } from "../model/crann.model";
2
- export declare function createCrannStateHook<TConfig extends Record<string, ConfigItem<any>>>(config: TConfig): (context?: string) => {
1
+ import { AnyConfig, DerivedState } from "../model/crann.model";
2
+ export declare function createCrannStateHook<TConfig extends AnyConfig>(config: TConfig): (context?: string) => {
3
3
  useStateItem: <K extends keyof DerivedState<TConfig>>(key: K) => readonly [DerivedState<TConfig>[K], (newValue: DerivedState<TConfig>[K]) => void];
4
4
  getState: () => DerivedState<TConfig>;
5
5
  setState: (newState: Partial<DerivedState<TConfig>>) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crann",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "description": "Effortless State Synchronization for Web Extensions",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",