ExNtfy.Publish.Options (ex_ntfy v0.1.1)

Copy Markdown View Source

Validates publish options and encodes them for ntfy's three publish shapes:

  • to_json_body/2 — the JSON publish (POST /, §1.3): most options become body fields; header-only options come back as headers for the same request.
  • to_headers/1 — the raw-body publish (POST /<topic>, §1.2): every option becomes its canonical X- header, RFC 2047-encoding non-ASCII values.
  • to_query/1 — the webhook-style publish (GET /<topic>/trigger): every option becomes a query parameter.

All three validate first, so a mistyped option raises NimbleOptions.ValidationError instead of silently dropping a feature.

Options

  • :message (String.t/0) - Message body. On the JSON path this is normally the positional argument to ExNtfy.publish/3; as an option it matters for ExNtfy.publish_raw/3 (e.g. an inline template) and ExNtfy.trigger/2.

  • :title (String.t/0) - Notification title.

  • :priority - 1..5 or :min | :low | :default | :high | :max | :urgent.

  • :tags - Tags/emoji shortcodes; atoms and strings mix, order is preserved.

  • :markdown (boolean/0) - Render the message body as Markdown.

  • :delay - Scheduled delivery: a DateTime, a non-negative unix timestamp, or a string ntfy understands ("30m", "tomorrow, 3pm").

  • :click (String.t/0) - URL opened when the notification is tapped.

  • :icon (String.t/0) - JPEG/PNG URL used as the notification icon.

  • :attach (String.t/0) - Attach a file by URL.

  • :filename (String.t/0) - Attachment filename override.

  • :actions - Up to 3 action buttons: ExNtfy.Action structs, ntfy-shaped maps, or a raw JSON string passed through untouched.

  • :email - Forward to an e-mail address, or true for the account's verified address.

  • :call - Phone call with the message read out: a number, or true for the verified one.

  • :sequence_id (String.t/0) - Sequence ID for the update/clear/delete lifecycle.

  • :cache (boolean/0) - false sends X-Cache: no (deliver only to live subscribers).

  • :firebase (boolean/0) - false sends X-Firebase: no (don't forward to FCM).

  • :unified_push (boolean/0) - true sends X-UnifiedPush: 1. Only for UnifiedPush apps.

  • :template - true for inline templating, :github | :grafana | :alertmanager for pre-defined templates, or a custom server-side template name.

  • :poll_id (String.t/0) - Internal (iOS instant notifications); pass-through only.

Summary

Types

Any publish option from the schema above.

Functions

RFC 2047 B-encodes a header value if it contains non-ASCII bytes; pure ASCII passes through untouched.

Encodes every option to its canonical X- header for a raw-body publish.

Encodes options for a JSON publish (POST /).

Encodes every option to a query parameter for the webhook-style publish.

Types

option()

@type option() :: {atom(), term()}

Any publish option from the schema above.

Functions

rfc2047_encode(value)

@spec rfc2047_encode(String.t()) :: String.t()

RFC 2047 B-encodes a header value if it contains non-ASCII bytes; pure ASCII passes through untouched.

Examples

iex> ExNtfy.Publish.Options.rfc2047_encode("all ASCII")
"all ASCII"

iex> ExNtfy.Publish.Options.rfc2047_encode("Grüße 👋")
"=?UTF-8?B?R3LDvMOfZSDwn5GL?="

to_headers(opts)

@spec to_headers([option()]) :: [{String.t(), String.t()}]

Encodes every option to its canonical X- header for a raw-body publish.

Non-ASCII values are RFC 2047 B-encoded via rfc2047_encode/1.

Examples

iex> ExNtfy.Publish.Options.to_headers(title: "Backup done", tags: [:warning, :backup])
[{"x-title", "Backup done"}, {"x-tags", "warning,backup"}]

iex> ExNtfy.Publish.Options.to_headers(delay: ~U[2026-07-05 12:00:00Z], template: true)
[{"x-delay", "1783252800"}, {"x-template", "yes"}]

to_json_body(topic, opts)

@spec to_json_body(String.t(), [option()]) :: {map(), [{String.t(), String.t()}]}

Encodes options for a JSON publish (POST /).

Returns {body, headers}: the JSON body map (string keys, always including "topic") plus the headers for the header-only options (:cache, :firebase, :unified_push, :template, :poll_id).

Examples

iex> ExNtfy.Publish.Options.to_json_body("alerts", message: "hi", priority: :high)
{%{"topic" => "alerts", "message" => "hi", "priority" => 4}, []}

iex> ExNtfy.Publish.Options.to_json_body("alerts", email: true, cache: false)
{%{"topic" => "alerts", "email" => "yes"}, [{"x-cache", "no"}]}

to_query(opts)

@spec to_query([option()]) :: keyword(String.t())

Encodes every option to a query parameter for the webhook-style publish.

Values match the header encoding, but are left raw — URL encoding covers UTF-8, so no RFC 2047 here.

Examples

iex> ExNtfy.Publish.Options.to_query(priority: :urgent, unified_push: true)
[priority: "5", up: "1"]