# `PhoenixKitKnowledgeBase.Events`
[🔗](https://github.com/BeamLabEU/phoenix_kit_knowledge_base/blob/v0.1.0/lib/phoenix_kit_knowledge_base/events.ex#L1)

PubSub notifications so a vault open in two browsers — or two people — stays
current.

One topic per vault, carrying every change in it. A per-note topic was the
obvious alternative and is worse: a viewer would need two subscriptions,
changes to *other* notes (which move the sidebar, the backlinks panel and the
unresolved list) would need the vault topic anyway, and a subscriber to both
would receive every note event twice.

## Origin

Every message carries the pid that caused it, and subscribers ignore their
own. Without that, the browser that just saved would immediately be told its
own note changed and offer to reload it from itself.

## What this is not

This keeps *separate* notes in sync and tells you when the note you are
reading changed underneath you. Merging two people's keystrokes into one note
is `Leaf.Collab`'s job, not this module's — see
`PhoenixKitKnowledgeBase.Collab`. The one place the two meet is
`note_conflict/2`, because a live-editing session that can no longer save has
no other way to say so.

# `message`

```elixir
@type message() ::
  {:kb_note_saved, map()}
  | {:kb_note_deleted, map()}
  | {:kb_vault_changed, map()}
  | {:kb_note_conflict, map()}
```

A change worth telling other sessions about.

# `note_conflict`

```elixir
@spec note_conflict(String.t(), String.t()) :: :ok
```

Announce that a live-editing session can no longer save.

Sent when the collaboration store refuses a flush because the file moved
underneath the session. Leaf 0.6's room recorded the conflict, stopped
writing and told nobody, so this was the only warning anyone got. Leaf ≥ 0.8
(what core admits today) also announces `{:leaf_conflict, …}` on its own
topic; this stays until the vault page handles that one itself — see
`PhoenixKitKnowledgeBase.Collab.Store`.

Carries no origin check on the receiving side: everyone in that note needs to
know, including whoever caused it.

# `note_deleted`

```elixir
@spec note_deleted(map()) :: :ok
```

Announce that a note is gone.

# `note_saved`

```elixir
@spec note_saved(map()) :: :ok
```

Announce that a note's content changed.

`hash` lets a receiver tell "somebody saved the bytes I already have" (a
rescan re-stamping an mtime, say) from a real edit it should react to.

# `own?`

```elixir
@spec own?(map()) :: boolean()
```

Whether a message came from this process.

Subscribers use it to skip their own writes.

# `subscribe`

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

Subscribe the calling process to a vault's changes.

# `vault_changed`

```elixir
@spec vault_changed(String.t(), atom()) :: :ok
```

Announce a change to the vault's shape rather than to one note's text —
a folder added or removed, or a rescan that touched many things at once.

A rescan sends this once instead of a note event per file: reindexing a
thousand-note vault should not put a thousand messages through every open
browser to say the same thing.

# `vault_topic`

```elixir
@spec vault_topic(String.t()) :: String.t()
```

The topic carrying every change in one vault.

---

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