# `WardrikTriggers`

Asks agents something on a clock, when a feed has new entries, or when a service sends a
webhook.

    children = [
      {WardrikTriggers, name: MyApp.Triggers, store: store, target: {MyApp.Agents, []}}
    ]

    :ok =
      WardrikTriggers.put(MyApp.Triggers, "acme/digest", [
        %{"name" => "daily", "every" => "0 9 * * *", "prompt" => "Write today's update."}
      ])

Each run happens once in the cluster, on the node that claims it first. It asks the agent
through the `WardrikTriggers.Target` given as `:target`.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `deliver`

```elixir
@spec deliver(atom(), String.t(), String.t(), WardrikTriggers.Webhook.request()) ::
  :ok | {:error, :not_found | :busy | :no_agent | :failed}
```

Asks `agent_id` about a request sent to its webhook trigger `name`.

The request must verify against the trigger's secret. See `WardrikTriggers.Webhook`. A request
already asked about returns `:ok` and asks nothing.

Returns `{:error, :not_found}` if the trigger doesn't exist, isn't a webhook, or the request
fails to verify. Otherwise returns `{:error, status}` when the agent wasn't asked.

# `list`

```elixir
@spec list(atom(), String.t()) :: [{WardrikTriggers.Trigger.t(), DateTime.t() | nil}]
```

Returns the triggers of `agent_id`, each with its next run. A webhook's next run is `nil`.

# `put`

```elixir
@spec put(atom(), String.t(), [map()]) :: :ok | {:error, String.t() | term()}
```

Replaces the triggers of `agent_id` with those `fields` describe.

A trigger whose `every` and `timezone` are unchanged keeps its next run. Returns
`{:error, message}` if any trigger is invalid, and changes nothing. See `WardrikTriggers.Trigger`
for the keys.

    :ok =
      WardrikTriggers.put(MyApp.Triggers, "acme/digest", [
        %{"name" => "daily", "every" => "0 9 * * *", "prompt" => "Write today's update."}
      ])

Each trigger is its own write. It sets the new triggers first, then removes the others. If a
write fails, it stops there and returns `{:error, reason}`: the triggers written before it are
changed, the rest are as they were. Call `put/3` again with the same `fields` to finish.

# `reconcile`

```elixir
@spec reconcile(atom()) :: :ok
```

Reads every trigger from the store again. Each node does this every `:reconcile` milliseconds.

# `remove`

```elixir
@spec remove(atom(), String.t(), String.t()) :: :ok | {:error, :not_found | term()}
```

Removes the trigger `name` of `agent_id`. Returns `{:error, :not_found}` if it has none, or
`{:error, reason}` if the store fails.

# `set`

```elixir
@spec set(atom(), String.t(), map()) ::
  {:ok, WardrikTriggers.Trigger.t()} | {:error, String.t() | term()}
```

Adds or replaces one trigger of `agent_id`, by its name.

Returns `{:error, message}` if the trigger is invalid, or `{:error, reason}` if the store fails.

# `start_link`

```elixir
@spec start_link(keyword()) :: Supervisor.on_start()
```

Starts the triggers.

    WardrikTriggers.start_link(name: MyApp.Triggers, store: store, target: {MyApp.Triggered, []})

## Options

  * `:name` - required. What you pass to every other function.
  * `:store` - required. The `WardrikStore` triggers are kept in.
  * `:target` - required. A `WardrikTriggers.Target`, as `{module, config}`.
  * `:req_options` - `Req` options for reading feeds. `[]` unless set.
  * `:reconcile` - milliseconds between each node reading every trigger again, or `:infinity`.
    `60_000` unless set.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
