Jido.Messaging.BridgeRegistry (Jido Messaging v1.0.0)

Copy Markdown View Source

Channel bridge discovery and lookup.

Provides a centralized registry for channel bridges, enabling runtime discovery of available channels, their capabilities, and associated adapters.

Usage

Register bridges at application startup:

# In your application.ex or a supervisor
BridgeRegistry.register(BridgePlugin.from_adapter(MyApp.TelegramAdapter))
BridgeRegistry.register(BridgePlugin.from_adapter(MyApp.DiscordAdapter))

Query registered bridges:

BridgeRegistry.list_bridges()
BridgeRegistry.get_bridge(:telegram)
BridgeRegistry.capabilities(:telegram)

Implementation

Uses an ETS table for storage, which provides fast concurrent reads. The table is created on first access and persists for the lifetime of the BEAM.

Summary

Functions

Loads bridge manifests and registers the resulting bridges with deterministic precedence.

Gets capabilities for a channel type.

Clears all registered bridges.

Gets an adapter module for a channel type and adapter kind.

Gets a channel module by its type.

Gets a bridge by its channel type.

Gets a bridge by its channel type, raising if not found.

Checks if a channel type supports a specific capability.

Lists all registered bridges.

Lists all channel types that have been registered.

Registers a bridge in the registry.

Unregisters a bridge from the registry.

Types

bootstrap_result()

@type bootstrap_result() :: %{
  registered_bridge_ids: [atom()],
  degraded_diagnostics: [manifest_diagnostic()],
  collision_diagnostics: [collision_diagnostic()]
}

collision_diagnostic()

@type collision_diagnostic() :: %{
  type: :bridge_id_collision,
  bridge_id: atom(),
  policy: manifest_collision_policy(),
  winning_path: String.t(),
  discarded_path: String.t()
}

manifest_collision_policy()

@type manifest_collision_policy() :: :prefer_first | :prefer_last

manifest_diagnostic()

@type manifest_diagnostic() :: %{
  :policy => :fatal_required_bridge_error | :degraded_optional_bridge_error,
  :type => atom(),
  optional(:bridge_id) => atom(),
  optional(:path) => String.t(),
  reason: term()
}

Functions

bootstrap_from_manifests(opts \\ [])

@spec bootstrap_from_manifests(keyword()) ::
  {:ok, bootstrap_result()}
  | {:error, {:fatal_required_bridge_error, manifest_diagnostic()}}

Loads bridge manifests and registers the resulting bridges with deterministic precedence.

Options

  • :manifest_paths - Manifest file paths, wildcard patterns, or directories.
  • :required_bridges - Bridge IDs that must load successfully (atoms or strings).
  • :collision_policy - :prefer_first or :prefer_last when bridge IDs collide.
  • :clear_existing? - When true, clear the registry before registration.

Returns {:error, {:fatal_required_bridge_error, diagnostic}} for required failures. Optional bridge failures degrade with warnings and telemetry.

capabilities(channel_type)

@spec capabilities(atom()) :: [atom()]

Gets capabilities for a channel type.

Returns an empty list if the channel is not registered.

Examples

BridgeRegistry.capabilities(:telegram)
# => [:text, :image, :streaming]

BridgeRegistry.capabilities(:unknown)
# => []

clear()

@spec clear() :: :ok

Clears all registered bridges.

Primarily useful for testing.

get_adapter(channel_type, adapter_type)

@spec get_adapter(atom(), atom()) :: module() | nil

Gets an adapter module for a channel type and adapter kind.

Examples

BridgeRegistry.get_adapter(:telegram, :mentions)
# => MyApp.TelegramMentionsAdapter

get_adapter_module(channel_type)

@spec get_adapter_module(atom()) :: module() | nil

Gets a channel module by its type.

Returns nil if not registered.

Examples

BridgeRegistry.get_adapter_module(:telegram)
# => MyApp.TelegramAdapter

get_bridge(channel_type)

@spec get_bridge(atom()) :: Jido.Messaging.BridgePlugin.t() | nil

Gets a bridge by its channel type.

Examples

BridgeRegistry.get_bridge(:telegram)
# => %BridgePlugin{id: :telegram, ...}

BridgeRegistry.get_bridge(:unknown)
# => nil

get_bridge!(channel_type)

@spec get_bridge!(atom()) :: Jido.Messaging.BridgePlugin.t()

Gets a bridge by its channel type, raising if not found.

Examples

BridgeRegistry.get_bridge!(:telegram)
# => %BridgePlugin{id: :telegram, ...}

BridgeRegistry.get_bridge!(:unknown)
# => ** (KeyError) bridge not found: :unknown

has_capability?(channel_type, capability)

@spec has_capability?(atom(), atom()) :: boolean()

Checks if a channel type supports a specific capability.

Examples

BridgeRegistry.has_capability?(:telegram, :streaming)
# => true

list_bridges()

@spec list_bridges() :: [Jido.Messaging.BridgePlugin.t()]

Lists all registered bridges.

Examples

BridgeRegistry.list_bridges()
# => [%BridgePlugin{id: :telegram, ...}, %BridgePlugin{id: :discord, ...}]

list_channel_types()

@spec list_channel_types() :: [atom()]

Lists all channel types that have been registered.

Examples

BridgeRegistry.list_channel_types()
# => [:telegram, :discord, :slack]

register(bridge)

@spec register(Jido.Messaging.BridgePlugin.t()) :: :ok

Registers a bridge in the registry.

If a bridge with the same ID already exists, it will be replaced.

Examples

bridge = BridgePlugin.from_adapter(MyApp.TelegramAdapter)
BridgeRegistry.register(bridge)
# => :ok

unregister(channel_type)

@spec unregister(atom()) :: :ok

Unregisters a bridge from the registry.

Examples

BridgeRegistry.unregister(:telegram)
# => :ok