Bonfire.API.MastoCompat.PaginationHelpers (Bonfire v1.0.1-social-alpha.28)
View SourceShared pagination utilities for Mastodon-compatible REST API adapters.
Provides consistent pagination handling across all Mastodon API endpoints:
- Limit validation with configurable defaults and maximums
- Cursor-based pagination parameter handling (max_id, since_id, min_id)
- Link header generation for Mastodon-compatible pagination
Summary
Functions
Add Mastodon-compatible Link headers for pagination.
Simplified Link headers for adapters that use item IDs as cursors.
Convert pagination param keys from strings to atoms.
Build feed parameters from Mastodon-style params.
Build pagination opts from Mastodon-style params (max_id, since_id, min_id).
Encode a plain ID as a cursor with a given field map.
Encode a cursor for GraphQL query parameters.
Encode a cursor for use in Link headers.
Encode a plain ULID as a cursor.
Extract limit and determine pagination direction (first vs last).
Extract pagination cursors from Mastodon-style params.
Add cursor to opts if present in params.
Validate that an already-encoded cursor can be decoded properly.
Validate and normalize pagination limit.
Functions
Add Mastodon-compatible Link headers for pagination.
Generates RFC 5988 Link headers with next and prev relations
using the page_info cursors from GraphQL responses.
Options
:cursor_field- Field format for cursor encoding (default: {:activity, :id})
Examples
conn
|> add_link_headers(%{}, page_info, items)
# Sets Link header: <url?max_id=xyz>; rel="next", <url?min_id=abc>; rel="prev"
Simplified Link headers for adapters that use item IDs as cursors.
Use this when cursors are simply object IDs rather than encoded Paginator cursors.
Convert pagination param keys from strings to atoms.
Pagination module expects atom keys for :after, :before, :first, :last.
Build feed parameters from Mastodon-style params.
Converts Mastodon timeline parameters to Bonfire GraphQL format:
- Extracts and encodes pagination cursors (max_id, since_id, min_id)
- Determines limit with first/last based on cursor direction
- Atomizes pagination keys for GraphQL compatibility
Options
:default_limit- Default limit when not specified (default: 20):max_limit- Maximum allowed limit (default: 40)
Examples
iex> build_feed_params(%{"limit" => "10", "max_id" => "abc"}, %{"feed_name" => "my"})
%{filter: %{"feed_name" => "my", "time_limit" => 0}, after: "encoded...", first: 10}
Build pagination opts from Mastodon-style params (max_id, since_id, min_id).
Converts Mastodon cursor params to keyword list format for Bonfire queries.
Examples
iex> build_pagination_opts(%{"max_id" => "abc123"}, 20)
[limit: 20, after: "abc123"]
iex> build_pagination_opts(%{}, 40)
[limit: 40]
Encode a plain ID as a cursor with a given field map.
Examples
iex> encode_cursor("abc123", %{id: "abc123"})
{:ok, "base64_encoded_string"}
Encode a cursor for GraphQL query parameters.
Handles both already-encoded cursors and plain IDs:
- Already base64 encoded (from Link headers) → validate and pass through
- Plain ID (ULID) → create proper cursor map and encode
Returns {:ok, cursor} or {:error, reason}.
Encode a cursor for use in Link headers.
Handles:
- nil cursors (returns nil)
- Already-encoded base64 cursors (pass through)
- Plain IDs (encode with cursor field format)
- Map cursors (encode to base64)
Encode a plain ULID as a cursor.
Creates a cursor map matching Bonfire's cursor_fields format:
%{{:activity, :id} => id}
Extract limit and determine pagination direction (first vs last).
Relay pagination: "first" with "after", "last" with "before" With descending sort:
- "after" + "first" = older posts (max_id)
- "before" + "last" = newer posts (min_id/since_id)
Extract pagination cursors from Mastodon-style params.
Maps Mastodon pagination IDs to Relay cursor params:
- max_id → after (items AFTER cursor in descending list = older/lower IDs)
- since_id/min_id → before (items BEFORE cursor in descending list = newer/higher IDs)
Cursors are encoded as base64 for GraphQL compatibility.
Add cursor to opts if present in params.
Works with both keyword list opts and map opts.
Examples
iex> maybe_add_cursor([limit: 20], %{"max_id" => "abc"}, "max_id", :after)
[after: "abc", limit: 20]
iex> maybe_add_cursor(%{limit: 20}, %{"max_id" => "abc"}, "max_id", :after)
%{limit: 20, after: "abc"}
Validate that an already-encoded cursor can be decoded properly.
Validate and normalize pagination limit.
Options
:default- Default limit when nil or invalid (default: 40):max- Maximum allowed limit (default: 80)
Examples
iex> validate_limit(nil)
40
iex> validate_limit("20")
20
iex> validate_limit(100)
80
iex> validate_limit(nil, default: 20, max: 40)
20