# Storage

The storage system is a reactive client-side key-value store. Values are lazy-loaded, can be updated from the server, and trigger callbacks when they change.

## Accessing Storage

The global `storage` table (also available as `KOJA.storage`) is backed by a metatable. Simply reading a key registers an update listener for it:

```lua
local value = storage['myKey']
```

On the first read, the key is registered and its update event is subscribed. Subsequent reads return the cached value.

## Getting a Value

```lua
-- Direct read
local myData = storage['playerStats']

-- Returns false if the key has never been set
```

## Computed / Cached Values

Use the call syntax to compute and optionally cache a value with a timeout:

```lua
local value = storage(key, computeFunc, timeout)
```

| Parameter     | Type       | Description                                          |
| ------------- | ---------- | ---------------------------------------------------- |
| `key`         | `string`   | Storage key                                          |
| `computeFunc` | `function` | Called to produce the value if it is not cached yet  |
| `timeout`     | `number?`  | Milliseconds after which the cached value is cleared |

**Example**

```lua
-- Compute the nearest shop once and cache it for 10 seconds
local nearestShop = storage('nearestShop', function()
    return findNearestShop(GetEntityCoords(PlayerPedId()))
end, 10000)
```

## Reacting to Changes

### Via event

Any time a key is updated (from the server or locally), `koja-lib:callback_triggered` fires:

```lua
AddEventHandler('koja-lib:callback_triggered', function(key, newValue, oldValue)
    if key == 'playerStats' then
        print('Stats updated:', json.encode(newValue))
    end
end)
```

### Via key-specific event

```lua
AddEventHandler('koja-lib:update:playerStats', function(newValue)
    print('playerStats is now:', json.encode(newValue))
end)
```

## Updating from the Server

Trigger the update event on the client to push a new value:

```lua
-- Server script
TriggerClientEvent('koja-lib:update:playerStats', source, {
    kills  = 12,
    deaths = 3,
})
```

The client's `storage['playerStats']` will be updated and all registered callbacks will fire.

## Metadata Properties

Two properties are always available on the storage object:

| Property           | Value                                |
| ------------------ | ------------------------------------ |
| `storage.game`     | Result of `GetGameName()`            |
| `storage.resource` | Result of `GetCurrentResourceName()` |

## Example — Live HUD Data

```lua
-- Server: push health every 5 seconds
CreateThread(function()
    while true do
        Wait(5000)
        for _, id in ipairs(GetPlayers()) do
            local ped = GetPlayerPed(id)
            TriggerClientEvent('koja-lib:update:health', id, GetEntityHealth(ped))
        end
    end
end)

-- Client: draw health bar
AddEventHandler('koja-lib:callback_triggered', function(key, value)
    if key == 'health' then
        -- update your HUD
    end
end)

-- Also works immediately on first read
local hp = storage['health']
```

## Related pages

- [Getting Started](/koja-lib/getting-started) — Configuration and Installation for Getting Started.
- [API Reference](/koja-lib/api-reference) — Client API and Server API for API Reference.
- [Frameworks](/koja-lib/frameworks) — Custom Framework and Overview for Frameworks.
- [Inventory](/koja-lib/inventory) — Custom Inventory and Overview for Inventory.
- [Weapon](/koja-lib/weapon) — Utility function for reading the player's current weapon state.
- [Text UI](/koja-lib/text-ui) — A small on-screen prompt that shows an action key and a label.
