Skip to main content

Plugin System

The Rust appview's extension surface is the RecordSink trait (layers-storage::RecordSink). An operator who wants behavior beyond the four shipped backends (Postgres, Elasticsearch, Neo4j, Redis) ships their own crate with a struct that implements RecordSink and adds it to the MultiSink in the indexer binary.

The trait is async-trait-compatible so the sink list can be heterogeneous behind Arc<dyn RecordSink>:

#[async_trait::async_trait]
impl RecordSink for MyCustomSink {
async fn put_record(
&self,
did: &str,
rkey: &str,
record: &AnyRecord,
) -> Result<(), IndexerError> { ... }

async fn delete_record(
&self,
did: &str,
collection: &str,
rkey: &str,
) -> Result<(), IndexerError> { ... }
}

MultiSink invokes each inner sink sequentially; the first error short-circuits the rest, so a sink that may fail without invalidating the firehose pipeline (e.g. an analytics tap) should swallow its own errors before returning Ok(()).

The frontend has no plugin surface. Format importers, exporters, and visualizations all live as ordinary React components under layers/web/components/.