bark-apns 0.1.0

Direct APNs client for sending Bark notifications.
Documentation
# bark-apns

Direct APNs client for sending [Bark](https://github.com/Finb/Bark) notifications.

This crate talks to APNs directly with an iOS device token, bypassing the Bark
server entirely. Messages can also be sent with Bark-compatible encryption, so
notification content stays private while delivery remains fast and direct.

## Key Features

- **✨ First-class `serde` payloads**: Uses strongly typed payload models and `serde` serialization throughout, avoiding brittle hand-built JSON.
- **🛡️ Correct Bark encryption semantics**: Validates algorithm, mode, key, and IV up front, supports all Bark AES options, and serializes encrypted pushes exactly as Bark expects.
- **🚀 Lean, direct APNs delivery**: Sends straight to APNs with no third-party relay or self-hosted backend in the path, keeping delivery fast, simple, and private.

## Usage

### Send a simple message

```rust
use bark_apns::{Bark, Message};

fn main() -> bark_apns::Result<()> {
    let bark = Bark::new()?;
    let message = Message::new()
        .title("Deploy")
        .body("done")
        .group("ops");

    bark.send(&message, ["device-token-from-bark-app"])?;
    Ok(())
}
```

### Send a markdown message

```rust
use bark_apns::{Bark, Message};

fn main() -> bark_apns::Result<()> {
    let bark = Bark::new()?;
    let message = Message::new()
        .title("Deploy")
        .markdown("## Deploy\n\n- status: **done**\n- target: `production`");

    bark.send(&message, ["device-token-from-bark-app"])?;
    Ok(())
}
```

> [!NOTE]
> Bark parses Markdown with Apple's Swift Markdown package and its own renderer.
> It supports paragraphs, headings, block quotes, bold, italic, strikethrough,
> inline code, code blocks, links, images, ordered and unordered lists, nested
> lists, task-list checkboxes, soft breaks, and hard line breaks. In notification
> banners, Bark uses the rendered plain-text body and collapses repeated blank
> lines, so styling such as bold, italic, link color, and code font is not
> preserved there.

### Send an encrypted message

```rust
use bark_apns::{Bark, Encryption, EncryptionAlgorithm, EncryptionMode, Message};

fn main() -> bark_apns::Result<()> {
    let bark = Bark::new()?;
    let encryption = Encryption::new(
        EncryptionAlgorithm::AES128,
        EncryptionMode::CBC,
        "1234567890123456",
    )?;

    let message = Message::new()
        .title("Deploy")
        .body("done")
        .markdown("**Deploy** finished")
        .group("ops")
        .encryption(encryption);

    bark.send(&message, ["device-token-from-bark-app"])?;
    Ok(())
}
```

The payload is built with `serde`, not string concatenation. Encrypted pushes place
Bark request fields in the encrypted `ciphertext` JSON and leave only `ciphertext`
and `iv` in APNs custom user info.

## Error Handling

Library APIs return `bark_apns::Result<T>`, a typed `Result<T, bark_apns::Error>`.
Applications can still use `anyhow::Result` at their own boundary:

```rust
fn run() -> anyhow::Result<()> {
    bark_apns::Bark::new()?;
    Ok(())
}
```

## License

This project is licensed under the [MIT license](LICENSE).