defmodule Raxol.Plugin.API do @moduledoc """ Public API facade for plugin management operations. Delegates to `Raxol.Core.Runtime.Plugins.PluginManager` with graceful error handling when the manager process is not running. ## Usage Raxol.Plugin.API.load(MyPlugin, %{option: "value"}) Raxol.Plugin.API.enable(:my_plugin) Raxol.Plugin.API.list() """ @compile {:no_warn_undefined, [ Raxol.Core.Runtime.Plugins.PluginManager, Raxol.Core.Runtime.Plugins.PluginLifecycle ]} @type plugin_id :: atom() | String.t() @doc """ Loads a plugin module with optional configuration. """ @spec load(module(), map()) :: :ok | {:error, term()} def load(module, config \\ %{}) do call(fn -> Raxol.Core.Runtime.Plugins.PluginManager.load_plugin_by_module(module, config) end) end @doc """ Unloads a plugin by ID. """ @spec unload(plugin_id()) :: :ok | {:error, term()} def unload(plugin_id) do call(fn -> Raxol.Core.Runtime.Plugins.PluginManager.unload_plugin(plugin_id) end) end @doc """ Enables a loaded plugin. """ @spec enable(plugin_id()) :: :ok | {:error, term()} def enable(plugin_id) do call(fn -> Raxol.Core.Runtime.Plugins.PluginManager.enable_plugin(plugin_id) end) end @doc """ Disables a plugin without unloading it. """ @spec disable(plugin_id()) :: :ok | {:error, term()} def disable(plugin_id) do call(fn -> Raxol.Core.Runtime.Plugins.PluginManager.disable_plugin(plugin_id) end) end @doc """ Lists all registered plugins. """ @spec list() :: [map()] | {:error, term()} def list do call(fn -> Raxol.Core.Runtime.Plugins.PluginManager.list_plugins() end) end @doc """ Gets the runtime state of a plugin. """ @spec get_state(plugin_id()) :: term() | {:error, term()} def get_state(plugin_id) do call(fn -> Raxol.Core.Runtime.Plugins.PluginManager.get_plugin_state(plugin_id) end) end @doc """ Reloads a plugin (unload + load). """ @spec reload(plugin_id()) :: :ok | {:error, term()} def reload(plugin_id) do call(fn -> Raxol.Core.Runtime.Plugins.PluginManager.reload_plugin(plugin_id) end) end @doc """ Checks whether a plugin is currently loaded. """ @spec loaded?(plugin_id()) :: boolean() | {:error, term()} def loaded?(plugin_id) do call(fn -> Raxol.Core.Runtime.Plugins.PluginManager.plugin_loaded?(plugin_id) end) end @doc """ Gets a plugin entry by ID. """ @spec get(plugin_id()) :: map() | nil | {:error, term()} def get(plugin_id) do call(fn -> Raxol.Core.Runtime.Plugins.PluginManager.get_plugin(plugin_id) end) end # Wraps calls in try/catch :exit for when the PluginManager/Lifecycle # GenServer is not running. @spec call((() -> result)) :: result | {:error, :plugin_manager_not_running} when result: term() defp call(fun) do fun.() catch :exit, _ -> {:error, :plugin_manager_not_running} end end