README.md

# Vault

[![CI](https://github.com/dimamik/vault/actions/workflows/ci.yml/badge.svg)](https://github.com/dimamik/vault/actions/workflows/ci.yml)
[![License](https://img.shields.io/hexpm/l/vault.svg)](https://github.com/dimamik/vault/blob/main/LICENSE)
[![Version](https://img.shields.io/hexpm/v/vault.svg)](https://hex.pm/packages/vault)
[![Hex Docs](https://img.shields.io/badge/documentation-gray.svg)](https://hexdocs.pm/vault)

<!-- MDOC -->

Vault is a lightweight Elixir library for process-scoped global data storage that propagates to **linked** process children.

Due to Elixir's actor model nature, it's common for a process to have global context that is valid for every function call inside this process (and its children).

For example, this context can include:

- A user when processing a user's request
- A tenant in a multi-tenant application
- Rate limiting buckets/quotas
- Cache namespaces
- API or client versions
- And many more, depending on your application domain

---

Vault provides you a guarantee that the context is only defined once when calling `Vault.init/1`, so you won't override it by accident. However, if you need to split initializations, you can always use `Vault.unsafe_merge/1`, but the responsibility will fall on you.

## Usage

```elixir
# Initialize vault in parent process
Vault.init(current_user: %{id: 1, first_name: "Alice", role: "admin"})

# Access data from any linked child process
Task.async(fn ->
  user = Vault.get(:current_user)
  user.first_name # => "Alice"
end)

# Access data from the parent process itself
Vault.get(:current_user) # => %{id: 1, first_name: "Alice", role: "admin"}
```

## Why Vault?

Instead of **property-drilling context data through every function call**, Vault provides access to shared data across your process tree. When used for immutable data - this is a cleaner and more maintainable approach, simplifying cognitive load when reasoning about your code.

The data is initialized only once and is immutable (unless you explicitly call `unsafe_*` functions).

The API mirrors Elixir's `Map` module for familiar data access.

## Limitations

- Vault only propagates to **linked** processes. If you start a process without linking (e.g., `Task.start/1`), it won't have access to the vault.

<!-- MDOC -->

## Installation

```elixir
def deps do
  [
    {:vault, "~> 0.2.0"}
  ]
end
```