README.md

# NanoGlobalCache

🔒 **Lightweight global cache for Elixir** with expiration support and intelligent failure handling.

Perfect for caching OAuth tokens, API keys, and other time-sensitive data that shouldn't be repeatedly refreshed.

## Why NanoGlobalCache?

- ✅ **Smart caching**: Caches successes, retries failures on next fetch
- 🌍 **Global**: Shared across entire Erlang node
- 🔐 **Thread-safe**: Safe concurrent access via `:global.trans/2`
- ⏱️ **Expiration**: Time-based invalidation
- 📝 **Clean DSL**: Compile-time configuration with auto-generated functions
- ⚡ **Minimal overhead**: No background processes or setup

## Installation

```elixir
def deps do
  [{:nano_global_cache, "~> 0.1.0"}]
end
```

## Quick Example

```elixir
defmodule MyApp.TokenCache do
  use NanoGlobalCache

  cache :github do
    expires_in :timer.hours(1)
    fetch fn ->
      case GitHub.refresh_token() do
        {:ok, token} -> {:ok, token}
        :error -> :error
      end
    end
  end

  cache :slack do
    expires_in :timer.minutes(30)
    fetch fn -> SlackAPI.get_token() end
  end

  # Generated functions: fetch/1, fetch!/1, clear/1, clear_all/0
end
```

### Usage

```elixir
# Pattern match on result
{:ok, token} = MyApp.TokenCache.fetch(:github)

# Or use bang version
token = MyApp.TokenCache.fetch!(:github)

# Clear cache
MyApp.TokenCache.clear(:github)
MyApp.TokenCache.clear_all()
```

## How It Works

- **Successful results**: Cached with timestamp, returned until expiration
- **Failed results** (`:error`): Never cached, always retried on next call
- **Thread safety**: All operations use global Erlang transactions (`global.trans/2`)

## When to Use

This library is optimized for **lightweight data** like:
- OAuth tokens, API keys, JWT tokens
- Small configuration values
- Session identifiers
- Cached credentials

**NOT recommended for**:
- Large binary data (images, files, documents)
- High-frequency writes
- Performance-critical caching needs

NanoGlobalCache uses `:global` and `Agent` for simplicity and minimal overhead. It's designed for scenarios where performance impact is negligible and simplicity is valued over throughput.

## API Reference

### Define Caches
```elixir
cache :cache_name do
  expires_in milliseconds_to_expire
  fetch fn -> {:ok, value} or :error end
end
```

### Generated Functions
- `fetch(name)` → `{:ok, value}` or `:error`
- `fetch!(name)` → `value` or raises `RuntimeError`
- `clear(name)` → `:ok`
- `clear_all()` → `:ok`

## Implementation

- Spark DSL for compile-time configuration
- Erlang global agents for distributed storage
- Automatic function generation via transformers