Improve public API documentation

This commit is contained in:
2026-03-18 18:08:47 +01:00
parent 9014912e9d
commit 2225dfdc9e
13 changed files with 417 additions and 1 deletions

View File

@@ -1,12 +1,37 @@
defmodule Parrhesia.API.ACL do
@moduledoc """
Public ACL API and rule matching for protected sync traffic.
ACL checks are only applied when the requested subject overlaps with
`config :parrhesia, :acl, protected_filters: [...]`.
The intended flow is:
1. mark a subset of sync traffic as protected with `protected_filters`
2. persist pubkey-based grants with `grant/2`
3. call `check/3` during sync reads and writes
Unprotected subjects always return `:ok`.
"""
alias Parrhesia.API.RequestContext
alias Parrhesia.Protocol.Filter
alias Parrhesia.Storage
@doc """
Persists an ACL rule.
A typical rule looks like:
```elixir
%{
principal_type: :pubkey,
principal: "...64 hex chars...",
capability: :sync_read,
match: %{"kinds" => [5000], "#r" => ["tribes.accounts.user"]}
}
```
"""
@spec grant(map(), keyword()) :: :ok | {:error, term()}
def grant(rule, _opts \\ []) do
with {:ok, _stored_rule} <- Storage.acl().put_rule(%{}, normalize_rule(rule)) do
@@ -14,16 +39,39 @@ defmodule Parrhesia.API.ACL do
end
end
@doc """
Deletes ACL rules matching the given selector.
The selector is passed through to the configured storage adapter, which typically accepts an
id-based selector such as `%{id: rule_id}`.
"""
@spec revoke(map(), keyword()) :: :ok | {:error, term()}
def revoke(rule, _opts \\ []) do
Storage.acl().delete_rule(%{}, normalize_delete_selector(rule))
end
@doc """
Lists persisted ACL rules.
Supported filters are:
- `:principal_type`
- `:principal`
- `:capability`
"""
@spec list(keyword()) :: {:ok, [map()]} | {:error, term()}
def list(opts \\ []) do
Storage.acl().list_rules(%{}, normalize_list_opts(opts))
end
@doc """
Authorizes a protected sync read or write subject for the given request context.
Supported capabilities are `:sync_read` and `:sync_write`.
`opts[:context]` defaults to an empty `Parrhesia.API.RequestContext`, which means protected
subjects will fail with `{:error, :auth_required}` until authenticated pubkeys are present.
"""
@spec check(atom(), map(), keyword()) :: :ok | {:error, term()}
def check(capability, subject, opts \\ [])
@@ -44,6 +92,9 @@ defmodule Parrhesia.API.ACL do
def check(_capability, _subject, _opts), do: {:error, :invalid_acl_capability}
@doc """
Returns `true` when a filter overlaps the configured protected read surface.
"""
@spec protected_read?(map()) :: boolean()
def protected_read?(filter) when is_map(filter) do
case protected_filters() do
@@ -57,6 +108,9 @@ defmodule Parrhesia.API.ACL do
def protected_read?(_filter), do: false
@doc """
Returns `true` when an event matches the configured protected write surface.
"""
@spec protected_write?(map()) :: boolean()
def protected_write?(event) when is_map(event) do
case protected_filters() do

View File

@@ -1,6 +1,14 @@
defmodule Parrhesia.API.Admin do
@moduledoc """
Public management API facade.
This module exposes the DX-friendly control plane for administrative tasks. It wraps
storage-backed management methods and a set of built-in helpers for ACL, identity, sync,
and listener management.
`execute/3` accepts the same method names used by NIP-86 style management endpoints, while
the dedicated functions (`stats/1`, `health/1`, `list_audit_logs/1`) are easier to call
from Elixir code.
"""
alias Parrhesia.API.ACL
@@ -26,6 +34,22 @@ defmodule Parrhesia.API.Admin do
sync_sync_now
)
@doc """
Executes a management method by name.
Built-in methods include:
- `supportedmethods`
- `stats`
- `health`
- `list_audit_logs`
- `acl_grant`, `acl_revoke`, `acl_list`
- `identity_get`, `identity_ensure`, `identity_import`, `identity_rotate`
- `listener_reload`
- `sync_*`
Unknown methods are delegated to the configured `Parrhesia.Storage.Admin` implementation.
"""
@spec execute(String.t() | atom(), map(), keyword()) :: {:ok, map()} | {:error, term()}
def execute(method, params, opts \\ [])
@@ -41,6 +65,9 @@ defmodule Parrhesia.API.Admin do
def execute(method, _params, _opts),
do: {:error, {:unsupported_method, normalize_method_name(method)}}
@doc """
Returns aggregate relay stats plus nested sync stats.
"""
@spec stats(keyword()) :: {:ok, map()} | {:error, term()}
def stats(opts \\ []) do
with {:ok, relay_stats} <- relay_stats(),
@@ -49,6 +76,12 @@ defmodule Parrhesia.API.Admin do
end
end
@doc """
Returns the overall management health payload.
The top-level `"status"` is currently derived from sync health, while relay-specific health
details remain delegated to storage-backed management methods.
"""
@spec health(keyword()) :: {:ok, map()} | {:error, term()}
def health(opts \\ []) do
with {:ok, sync_health} <- Sync.sync_health(opts) do
@@ -60,6 +93,12 @@ defmodule Parrhesia.API.Admin do
end
end
@doc """
Lists persisted audit log entries from the configured admin storage backend.
Supported options are storage-adapter specific. The built-in admin execution path forwards
`:limit`, `:method`, and `:actor_pubkey`.
"""
@spec list_audit_logs(keyword()) :: {:ok, [map()]} | {:error, term()}
def list_audit_logs(opts \\ []) do
Storage.admin().list_audit_logs(%{}, opts)

View File

@@ -1,6 +1,15 @@
defmodule Parrhesia.API.Auth do
@moduledoc """
Shared auth and event validation helpers.
Public helpers for event validation and NIP-98 HTTP authentication.
This module is intended for callers that need a programmatic API surface:
- `validate_event/1` returns validator reason atoms.
- `compute_event_id/1` computes the canonical Nostr event id.
- `validate_nip98/3` and `validate_nip98/4` turn an `Authorization` header into a
shared auth context that can be reused by the rest of the API surface.
For transport-facing validation messages, see `Parrhesia.Protocol.validate_event/1`.
"""
alias Parrhesia.API.Auth.Context
@@ -8,18 +17,46 @@ defmodule Parrhesia.API.Auth do
alias Parrhesia.Auth.Nip98
alias Parrhesia.Protocol.EventValidator
@doc """
Validates a Nostr event and returns validator-friendly error atoms.
This is the low-level validation entrypoint used by the API surface. Unlike
`Parrhesia.Protocol.validate_event/1`, it preserves the raw validator reason so callers
can branch on it directly.
"""
@spec validate_event(map()) :: :ok | {:error, term()}
def validate_event(event), do: EventValidator.validate(event)
@doc """
Computes the canonical Nostr event id for an event payload.
The event does not need to be persisted first. This is useful when building or signing
events locally.
"""
@spec compute_event_id(map()) :: String.t()
def compute_event_id(event), do: EventValidator.compute_id(event)
@doc """
Validates a NIP-98 `Authorization` header using default options.
"""
@spec validate_nip98(String.t() | nil, String.t(), String.t()) ::
{:ok, Context.t()} | {:error, term()}
def validate_nip98(authorization, method, url) do
validate_nip98(authorization, method, url, [])
end
@doc """
Validates a NIP-98 `Authorization` header and returns a shared auth context.
The returned `Parrhesia.API.Auth.Context` includes:
- the decoded auth event
- the authenticated pubkey
- a `Parrhesia.API.RequestContext` with `caller: :http`
Supported options are forwarded to `Parrhesia.Auth.Nip98.validate_authorization_header/4`,
including `:max_age_seconds` and `:replay_cache`.
"""
@spec validate_nip98(String.t() | nil, String.t(), String.t(), keyword()) ::
{:ok, Context.t()} | {:error, term()}
def validate_nip98(authorization, method, url, opts)

View File

@@ -1,6 +1,10 @@
defmodule Parrhesia.API.Auth.Context do
@moduledoc """
Authenticated request details returned by shared auth helpers.
This is the higher-level result returned by `Parrhesia.API.Auth.validate_nip98/3` and
`validate_nip98/4`. The nested `request_context` is ready to be passed into the rest of the
public API surface.
"""
alias Parrhesia.API.RequestContext

View File

@@ -1,6 +1,17 @@
defmodule Parrhesia.API.Events do
@moduledoc """
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.
"""
alias Parrhesia.API.Events.PublishResult
@@ -29,6 +40,24 @@ defmodule Parrhesia.API.Events do
449
])
@doc """
Validates, authorizes, persists, and fans out an event.
Required options:
- `:context` - a `Parrhesia.API.RequestContext`
Supported options:
- `:max_event_bytes` - overrides the configured max encoded event size
- `: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
"""
@spec publish(map(), keyword()) :: {:ok, PublishResult.t()} | {:error, term()}
def publish(event, opts \\ [])
@@ -87,6 +116,22 @@ defmodule Parrhesia.API.Events do
def publish(_event, _opts), do: {:error, :invalid_event}
@doc """
Queries stored events plus any dynamic NIP-43 events visible to the caller.
Required options:
- `:context` - a `Parrhesia.API.RequestContext`
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.
"""
@spec query([map()], keyword()) :: {:ok, [map()]} | {:error, term()}
def query(filters, opts \\ [])
@@ -118,6 +163,22 @@ defmodule Parrhesia.API.Events do
def query(_filters, _opts), do: {:error, :invalid_filters}
@doc """
Counts events matching the given filters.
Required options:
- `:context` - a `Parrhesia.API.RequestContext`
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.
"""
@spec count([map()], keyword()) :: {:ok, non_neg_integer() | map()} | {:error, term()}
def count(filters, opts \\ [])

View File

@@ -1,6 +1,14 @@
defmodule Parrhesia.API.Events.PublishResult do
@moduledoc """
Result shape for event publish attempts.
This mirrors relay `OK` semantics:
- `accepted: true` means the event was accepted
- `accepted: false` means the event was rejected or identified as a duplicate
The surrounding call still returns `{:ok, result}` in both cases so callers can surface the
rejection message without treating it as a transport or process failure.
"""
defstruct [:event_id, :accepted, :message, :reason]

View File

@@ -1,15 +1,40 @@
defmodule Parrhesia.API.Identity do
@moduledoc """
Server-auth identity management.
Parrhesia uses a single server identity for flows that need the relay to sign events or
prove control of a pubkey.
Identity resolution follows this order:
1. `opts[:private_key]` or `opts[:configured_private_key]`
2. `Application.get_env(:parrhesia, :identity)`
3. the persisted file on disk
Supported options across this module:
- `:path` - overrides the identity file path
- `:private_key` / `:configured_private_key` - uses an explicit hex secret key
A configured private key is treated as read-only input and therefore cannot be rotated.
"""
alias Parrhesia.API.Auth
@typedoc """
Public identity metadata returned to callers.
"""
@type identity_metadata :: %{
pubkey: String.t(),
source: :configured | :persisted | :generated | :imported
}
@doc """
Returns the current server identity metadata.
This does not generate a new identity. If no configured or persisted identity exists, it
returns `{:error, :identity_not_found}`.
"""
@spec get(keyword()) :: {:ok, identity_metadata()} | {:error, term()}
def get(opts \\ []) do
with {:ok, identity} <- fetch_existing_identity(opts) do
@@ -17,6 +42,9 @@ defmodule Parrhesia.API.Identity do
end
end
@doc """
Returns the current identity, generating and persisting one when necessary.
"""
@spec ensure(keyword()) :: {:ok, identity_metadata()} | {:error, term()}
def ensure(opts \\ []) do
with {:ok, identity} <- ensure_identity(opts) do
@@ -24,6 +52,12 @@ defmodule Parrhesia.API.Identity do
end
end
@doc """
Imports an explicit secret key and persists it as the server identity.
The input map must contain `:secret_key` or `"secret_key"` as a 64-character lowercase or
uppercase hex string.
"""
@spec import(map(), keyword()) :: {:ok, identity_metadata()} | {:error, term()}
def import(identity, opts \\ [])
@@ -37,6 +71,12 @@ defmodule Parrhesia.API.Identity do
def import(_identity, _opts), do: {:error, :invalid_identity}
@doc """
Generates and persists a fresh server identity.
Rotation is rejected with `{:error, :configured_identity_cannot_rotate}` when the active
identity comes from configuration rather than the persisted file.
"""
@spec rotate(keyword()) :: {:ok, identity_metadata()} | {:error, term()}
def rotate(opts \\ []) do
with :ok <- ensure_rotation_allowed(opts),
@@ -46,6 +86,18 @@ defmodule Parrhesia.API.Identity do
end
end
@doc """
Signs an event with the current server identity.
The incoming event must already include the fields required to compute a Nostr id:
- `"created_at"`
- `"kind"`
- `"tags"`
- `"content"`
On success the returned event includes `"pubkey"`, `"id"`, and `"sig"`.
"""
@spec sign_event(map(), keyword()) :: {:ok, map()} | {:error, term()}
def sign_event(event, opts \\ [])
@@ -59,6 +111,9 @@ defmodule Parrhesia.API.Identity do
def sign_event(_event, _opts), do: {:error, :invalid_event}
@doc """
Returns the default filesystem path for the persisted server identity.
"""
def default_path do
Path.join([default_data_dir(), "server_identity.json"])
end

View File

@@ -1,6 +1,15 @@
defmodule Parrhesia.API.RequestContext do
@moduledoc """
Shared request context used across API and policy surfaces.
This struct carries caller identity and transport metadata through authorization and storage
boundaries.
The most important field for external callers is `authenticated_pubkeys`. For example:
- `Parrhesia.API.Events` uses it for read and write policy checks
- `Parrhesia.API.Stream` uses it for subscription authorization
- `Parrhesia.API.ACL` uses it when evaluating protected sync traffic
"""
defstruct authenticated_pubkeys: MapSet.new(),
@@ -23,6 +32,11 @@ defmodule Parrhesia.API.RequestContext do
metadata: map()
}
@doc """
Merges arbitrary metadata into the context.
Existing keys are overwritten by the incoming map.
"""
@spec put_metadata(t(), map()) :: t()
def put_metadata(%__MODULE__{} = context, metadata) when is_map(metadata) do
%__MODULE__{context | metadata: Map.merge(context.metadata, metadata)}

View File

@@ -1,6 +1,15 @@
defmodule Parrhesia.API.Stream do
@moduledoc """
In-process subscription API with relay-equivalent catch-up and live fanout semantics.
Subscriptions are process-local bridges. After subscribing, the caller receives messages in
the same order a relay client would expect:
- `{:parrhesia, :event, ref, subscription_id, event}` for catch-up and live events
- `{:parrhesia, :eose, ref, subscription_id}` after the initial replay finishes
This API requires a `Parrhesia.API.RequestContext` so read policies are applied exactly as
they would be for a transport-backed subscriber.
"""
alias Parrhesia.API.Events
@@ -9,6 +18,16 @@ defmodule Parrhesia.API.Stream do
alias Parrhesia.Policy.EventPolicy
alias Parrhesia.Protocol.Filter
@doc """
Starts an in-process subscription for a subscriber pid.
`opts[:context]` must be a `Parrhesia.API.RequestContext`.
On success the returned reference is both:
- the subscription handle used by `unsubscribe/1`
- the value embedded in emitted subscriber messages
"""
@spec subscribe(pid(), String.t(), [map()], keyword()) :: {:ok, reference()} | {:error, term()}
def subscribe(subscriber, subscription_id, filters, opts \\ [])
@@ -42,6 +61,11 @@ defmodule Parrhesia.API.Stream do
def subscribe(_subscriber, _subscription_id, _filters, _opts),
do: {:error, :invalid_subscription}
@doc """
Stops a subscription previously created with `subscribe/4`.
This function is idempotent. Unknown or already-stopped references return `:ok`.
"""
@spec unsubscribe(reference()) :: :ok
def unsubscribe(ref) when is_reference(ref) do
case Registry.lookup(Parrhesia.API.Stream.Registry, ref) do

View File

@@ -1,12 +1,45 @@
defmodule Parrhesia.API.Sync do
@moduledoc """
Sync server control-plane API.
This module manages outbound relay sync definitions and exposes runtime status for each
configured sync worker.
The main entrypoint is `put_server/2`. Accepted server maps are normalized into a stable
internal shape and persisted by the sync manager. The expected input shape is:
```elixir
%{
"id" => "tribes-primary",
"url" => "wss://relay-a.example/relay",
"enabled?" => true,
"auth_pubkey" => "...64 hex chars...",
"filters" => [%{"kinds" => [5000]}],
"mode" => "req_stream",
"overlap_window_seconds" => 300,
"auth" => %{"type" => "nip42"},
"tls" => %{
"mode" => "required",
"hostname" => "relay-a.example",
"pins" => [%{"type" => "spki_sha256", "value" => "..."}]
},
"metadata" => %{}
}
```
Most functions accept `:manager` or `:name` in `opts` to target a non-default manager.
"""
alias Parrhesia.API.Sync.Manager
@typedoc """
Normalized sync server configuration returned by the sync manager.
"""
@type server :: map()
@doc """
Creates or replaces a sync server definition.
"""
@spec put_server(map(), keyword()) :: {:ok, server()} | {:error, term()}
def put_server(server, opts \\ [])
@@ -16,6 +49,9 @@ defmodule Parrhesia.API.Sync do
def put_server(_server, _opts), do: {:error, :invalid_server}
@doc """
Removes a stored sync server definition and stops its worker if it is running.
"""
@spec remove_server(String.t(), keyword()) :: :ok | {:error, term()}
def remove_server(server_id, opts \\ [])
@@ -25,6 +61,11 @@ defmodule Parrhesia.API.Sync do
def remove_server(_server_id, _opts), do: {:error, :invalid_server_id}
@doc """
Fetches a single normalized sync server definition.
Returns `:error` when the server id is unknown.
"""
@spec get_server(String.t(), keyword()) :: {:ok, server()} | :error | {:error, term()}
def get_server(server_id, opts \\ [])
@@ -34,11 +75,17 @@ defmodule Parrhesia.API.Sync do
def get_server(_server_id, _opts), do: {:error, :invalid_server_id}
@doc """
Lists all configured sync servers, including their runtime state.
"""
@spec list_servers(keyword()) :: {:ok, [server()]} | {:error, term()}
def list_servers(opts \\ []) when is_list(opts) do
Manager.list_servers(manager_name(opts))
end
@doc """
Marks a sync server as running and reconciles its worker state.
"""
@spec start_server(String.t(), keyword()) :: :ok | {:error, term()}
def start_server(server_id, opts \\ [])
@@ -48,6 +95,9 @@ defmodule Parrhesia.API.Sync do
def start_server(_server_id, _opts), do: {:error, :invalid_server_id}
@doc """
Stops a sync server and records a disconnect timestamp in runtime state.
"""
@spec stop_server(String.t(), keyword()) :: :ok | {:error, term()}
def stop_server(server_id, opts \\ [])
@@ -57,6 +107,9 @@ defmodule Parrhesia.API.Sync do
def stop_server(_server_id, _opts), do: {:error, :invalid_server_id}
@doc """
Triggers an immediate sync run for a server.
"""
@spec sync_now(String.t(), keyword()) :: :ok | {:error, term()}
def sync_now(server_id, opts \\ [])
@@ -66,6 +119,11 @@ defmodule Parrhesia.API.Sync do
def sync_now(_server_id, _opts), do: {:error, :invalid_server_id}
@doc """
Returns runtime counters and timestamps for a single sync server.
Returns `:error` when the server id is unknown.
"""
@spec server_stats(String.t(), keyword()) :: {:ok, map()} | :error | {:error, term()}
def server_stats(server_id, opts \\ [])
@@ -75,16 +133,25 @@ defmodule Parrhesia.API.Sync do
def server_stats(_server_id, _opts), do: {:error, :invalid_server_id}
@doc """
Returns aggregate counters across all configured sync servers.
"""
@spec sync_stats(keyword()) :: {:ok, map()} | {:error, term()}
def sync_stats(opts \\ []) when is_list(opts) do
Manager.sync_stats(manager_name(opts))
end
@doc """
Returns a health summary for the sync subsystem.
"""
@spec sync_health(keyword()) :: {:ok, map()} | {:error, term()}
def sync_health(opts \\ []) when is_list(opts) do
Manager.sync_health(manager_name(opts))
end
@doc """
Returns the default filesystem path for persisted sync server state.
"""
def default_path do
Path.join([default_data_dir(), "sync_servers.json"])
end

View File

@@ -1,6 +1,9 @@
defmodule Parrhesia.Config do
@moduledoc """
Runtime configuration cache backed by ETS.
The application environment is copied into ETS at startup so hot-path reads do not need to
traverse the application environment repeatedly.
"""
use GenServer
@@ -8,6 +11,9 @@ defmodule Parrhesia.Config do
@table __MODULE__
@root_key :config
@doc """
Starts the config cache server.
"""
def start_link(init_arg \\ []) do
GenServer.start_link(__MODULE__, init_arg, name: __MODULE__)
end
@@ -26,6 +32,9 @@ defmodule Parrhesia.Config do
{:ok, %{}}
end
@doc """
Returns the cached top-level Parrhesia application config.
"""
@spec all() :: map() | keyword()
def all do
case :ets.lookup(@table, @root_key) do
@@ -34,6 +43,11 @@ defmodule Parrhesia.Config do
end
end
@doc """
Reads a nested config value by path.
The path may traverse maps or keyword lists. Missing paths return `default`.
"""
@spec get([atom()], term()) :: term()
def get(path, default \\ nil) when is_list(path) do
case fetch(path) do

View File

@@ -1,6 +1,15 @@
defmodule Parrhesia.Protocol do
@moduledoc """
Nostr protocol message decode/encode helpers.
This module is transport-oriented: it turns websocket payloads into structured tuples and
back again.
For programmatic API calls inside the application, prefer the `Parrhesia.API.*` modules.
In particular:
- `validate_event/1` returns user-facing error strings
- `Parrhesia.API.Auth.validate_event/1` returns machine-friendly validator atoms
"""
alias Parrhesia.Protocol.EventValidator
@@ -41,6 +50,9 @@ defmodule Parrhesia.Protocol do
@count_options_keys MapSet.new(["hll", "approximate"])
@doc """
Decodes a client websocket payload into a structured protocol tuple.
"""
@spec decode_client(binary()) :: {:ok, client_message()} | {:error, decode_error()}
def decode_client(payload) when is_binary(payload) do
with {:ok, decoded} <- decode_json(payload) do
@@ -48,6 +60,9 @@ defmodule Parrhesia.Protocol do
end
end
@doc """
Validates an event and returns relay-facing error strings.
"""
@spec validate_event(event()) :: :ok | {:error, String.t()}
def validate_event(event) do
case EventValidator.validate(event) do
@@ -56,6 +71,9 @@ defmodule Parrhesia.Protocol do
end
end
@doc """
Encodes a relay message tuple into the JSON frame sent to clients.
"""
@spec encode_relay(relay_message()) :: binary()
def encode_relay(message) do
message
@@ -63,6 +81,9 @@ defmodule Parrhesia.Protocol do
|> JSON.encode!()
end
@doc """
Converts a decode error into the relay notice string that should be sent to a client.
"""
@spec decode_error_notice(decode_error()) :: String.t()
def decode_error_notice(reason) do
case reason do

View File

@@ -4,6 +4,9 @@ defmodule Parrhesia.Storage do
Domain/runtime code should resolve behavior modules through this module instead of
depending on concrete adapter implementations directly.
Each accessor validates that the configured module is loaded and declares the expected
behaviour before returning it.
"""
@default_modules [
@@ -14,18 +17,33 @@ defmodule Parrhesia.Storage do
admin: Parrhesia.Storage.Adapters.Postgres.Admin
]
@doc """
Returns the configured events storage module.
"""
@spec events() :: module()
def events, do: fetch_module!(:events, Parrhesia.Storage.Events)
@doc """
Returns the configured moderation storage module.
"""
@spec moderation() :: module()
def moderation, do: fetch_module!(:moderation, Parrhesia.Storage.Moderation)
@doc """
Returns the configured ACL storage module.
"""
@spec acl() :: module()
def acl, do: fetch_module!(:acl, Parrhesia.Storage.ACL)
@doc """
Returns the configured groups storage module.
"""
@spec groups() :: module()
def groups, do: fetch_module!(:groups, Parrhesia.Storage.Groups)
@doc """
Returns the configured admin storage module.
"""
@spec admin() :: module()
def admin, do: fetch_module!(:admin, Parrhesia.Storage.Admin)