README.md

# topics

Topic-based publish/subscribe for Gleam with automatic dead subscriber cleanup.

Messages can be of any type — each `PubSub(msg)` instance is isolated by the message type, enforced at compile time.

## Installation

```sh
gleam add topics
```

```toml
[dependencies]
topics = "~> 1.0"
```

## Usage

```gleam
import gleam/erlang/process
import topics

pub fn main() {
  let assert Ok(ps) = topics.start()

  let subject = process.new_subject()
  topics.subscribe(ps, "events", subject)
  topics.broadcast(ps, "events", "something happened")

  let assert Ok(msg) = process.receive(subject, within: 1000)

  topics.unsubscribe(ps, "events", subject)

  // Inspect topics and subscriber counts
  let topics = topics.list_topics(ps)
  let count = topics.subscriber_count(ps, "events")
}
```

### Generic messages

The topics package is generic over the message type. The type is inferred from usage:

```gleam
// PubSub(Int) — inferred from the broadcast call
let assert Ok(int_ps) = topics.start()
let sub = process.new_subject()
topics.subscribe(int_ps, "counts", sub)
topics.broadcast(int_ps, "counts", 42)
```

Custom types work the same way:

```gleam
type Event {
  UserJoined(name: String)
  UserLeft(name: String)
}

let assert Ok(event_ps) = topics.start()
let sub = process.new_subject()
topics.subscribe(event_ps, "lobby", sub)
topics.broadcast(event_ps, "lobby", UserJoined("Alice"))
```

## Supervisor integration

Use `start_linked` to embed the topics server in a supervision tree:

```gleam
import gleam/otp/static_supervisor as supervisor

pub fn main() {
  let assert Ok(_) =
    supervisor.new()
    |> supervisor.add(topics.start_linked)
    |> supervisor.start()

  // topics is now supervised and will be restarted on failure
}
```

## Known limitations

- **Single-node only.** No support for distributed Erlang clusters. All publishers and subscribers must run on the same BEAM node.
- **Sequential broadcast.** Messages are delivered to subscribers sequentially within each broadcast call. Latency grows linearly with subscriber count.
- **Fire-and-forget delivery.** No delivery acknowledgement or guarantee. If a subscriber's mailbox is full, messages may be silently dropped.

## License

Apache-2.0