Parrhesia.API.Events (parrhesia v0.14.0)

Copy Markdown

Canonical event publish, query, and count API.

This is the main in-process API for working with Nostr events. It applies the same core validation and policy checks used by the relay edge, but without going through a socket or HTTP transport.

All public functions expect opts[:context] to contain a Parrhesia.API.RequestContext. That context drives authorization, caller attribution, and downstream policy behavior.

publish/2 intentionally returns {:ok, %PublishResult{accepted: false}} for policy and storage rejections so callers can mirror relay OK semantics without treating a rejected event as a process error.

Summary

Functions

Counts events matching the given filters.

Paginates stored events for a single filter using keyset cursors.

Validates, authorizes, persists, and fans out an event.

Batch variant of publish/2 for trusted sync paths that have already received a page of remote events in one transport frame.

Queries stored events plus any dynamic NIP-43 events visible to the caller.

Functions

count(filters, opts \\ [])

@spec count(
  [map()],
  keyword()
) :: {:ok, non_neg_integer() | map()} | {:error, term()}

Counts events matching the given filters.

Required options:

Supported options:

  • :validate_filters? - skips filter validation when false
  • :authorize_read? - skips read policy checks when false
  • :options - when set to a map, returns a NIP-45-style payload instead of a bare integer

When opts[:options] is a map, the result shape is %{"count" => count, "approximate" => false}. If opts[:options]["hll"] is true and the feature is enabled, an "hll" field is included.

paginate(filter, opts \\ [])

@spec paginate(
  map(),
  keyword()
) :: {:ok, [map()]} | {:error, term()}

Paginates stored events for a single filter using keyset cursors.

Unlike query/2, this bypasses NIP-01 newest-first ordering and any dynamic NIP-43 expansion; it returns the persisted-event slice that strictly satisfies the keyset bounds in the requested order. Intended for the Parrhesia SYNC-PAGE wire frame.

Required options:

Supported options:

  • :order - :asc (default) or :desc
  • :limit - max events returned (caller is responsible for capping)
  • :after_key, :until_key - {created_at, event_id_hex} keyset bounds
  • :validate_filters?, :authorize_read? - same semantics as query/2

publish(event, opts \\ [])

@spec publish(
  map(),
  keyword()
) :: {:ok, Parrhesia.API.Events.PublishResult.t()} | {:error, term()}

Validates, authorizes, persists, and fans out an event.

Required options:

Supported options:

  • :max_event_bytes - overrides the configured max encoded event size
  • :role, :path, :private_key, :configured_private_key - forwarded to the NIP-43 helper flow

Return semantics:

  • {:ok, %PublishResult{accepted: true}} for accepted events
  • {:ok, %PublishResult{accepted: false}} for rejected or duplicate events
  • {:error, :invalid_context} only when the call itself is malformed

publish_many(events, opts \\ [])

@spec publish_many(
  [map()],
  keyword()
) :: {:ok, [Parrhesia.API.Events.PublishResult.t()]} | {:error, term()}

Batch variant of publish/2 for trusted sync paths that have already received a page of remote events in one transport frame.

Untrusted callers still run full event validation. Trusted sync callers skip duplicate signature/hash/future-timestamp validation because the source Parrhesia node already validated before storage. Regular persisted events are inserted with a storage-level batch operation and dispatched as a batch. Control and ephemeral events fall back to publish/2 because their side effects are not bulk-safe.

query(filters, opts \\ [])

@spec query(
  [map()],
  keyword()
) :: {:ok, [map()]} | {:error, term()}

Queries stored events plus any dynamic NIP-43 events visible to the caller.

Required options:

Supported options:

  • :max_filter_limit - overrides the configured per-filter limit
  • :validate_filters? - skips filter validation when false
  • :authorize_read? - skips read policy checks when false

The skip flags are primarily for internal composition, such as Parrhesia.API.Stream. External callers should normally leave them enabled.