# Throne Wishlist

This plugin receives signed Throne wishlist events through Lumi's core webhook
framework, logs every payload, deduplicates by `event_id`, and can publish
messages to configured platform destinations.

## Setup

1. Install the core webhook framework patch.
2. Install and enable this plugin.
3. Open **Plugins -> Throne Wishlist** as an administrator.
4. Create an endpoint with a short identifier.
5. Copy the generated `/webhooks/throne/{identifier}-{uuid}` URL into Throne's
   webhook integration.

Throne requires an HTTPS subscriber URL in production. Configure Lumi behind an
HTTPS reverse proxy and set `public_base_url` in Lumi settings when available.

## Security and Delivery

Throne requests are verified with the Ed25519 public key published in Throne's
current webhook documentation. Verification uses
`X-Signature-Timestamp + "." + the exact raw request body`, with a five-minute
replay window. Invalid signatures never trigger platform messages.

Authentic duplicate `event_id` values receive a successful response without
repeating side effects. Supported events are `gift_purchased`,
`contribution_purchased`, and `gift_crowdfunded`. Unknown authentic events are
logged and acknowledged without sending messages.

## Debug Mode

The admin Debug modal uses a transient Server-Sent Events session. It only shows
payloads received after the session starts. Closing the modal or disconnecting
ends the session. Sessions expire after five minutes without payloads and after
30 minutes total. Debug payloads are not stored separately; all webhook payloads
are already written to Lumi's internal logs.

## Destinations

- Discord requires a regular guild text channel where the bot can view and send.
- Twitch uses the first connected Lumi Twitch channel.
- YouTube uses Lumi's active live-chat sender.
- Kick remains unavailable until Lumi implements a send-message capability.

All destinations default to disabled. A failure on one destination does not
prevent delivery attempts to other enabled destinations.

## Placeholders

Common placeholders:

`{{plugin.throne_wishlist.contract_version}}`,
`{{plugin.throne_wishlist.event_id}}`,
`{{plugin.throne_wishlist.event_type}}`,
`{{plugin.throne_wishlist.webhook_identifier}}`,
`{{plugin.throne_wishlist.webhook_uuid}}`,
`{{plugin.throne_wishlist.received_at}}`,
`{{plugin.throne_wishlist.received_at_iso}}`,
`{{plugin.throne_wishlist.creator_id}}`,
`{{plugin.throne_wishlist.creator_username}}`,
`{{plugin.throne_wishlist.gifter_username}}`,
`{{plugin.throne_wishlist.message}}`,
`{{plugin.throne_wishlist.item_name}}`,
`{{plugin.throne_wishlist.item_thumbnail_url}}`,
`{{plugin.throne_wishlist.price}}`,
`{{plugin.throne_wishlist.amount}}`,
`{{plugin.throne_wishlist.currency}}`,
`{{plugin.throne_wishlist.is_surprise_gift}}`,
`{{plugin.throne_wishlist.price_display}}`,
`{{plugin.throne_wishlist.amount_display}}`,
`{{plugin.throne_wishlist.value}}`, and
`{{plugin.throne_wishlist.value_display}}`.

Documented data fields are also available with a `data.` prefix, such as
`{{plugin.throne_wishlist.data.item_name}}`. Legacy single-brace placeholders
still render for existing templates, but new templates should use the namespaced
double-brace syntax. Raw payload JSON is intentionally not available to
user-visible message templates. Unknown placeholders remain unchanged in
rendered messages. The admin page warns when they are saved.
