Server functions for items, usable items and stashes.
They call whichever inventory the server runs, or the framework's own item functions.

## Items

```lua
ObsiLib.items.add(source, 'water', 2)
ObsiLib.items.add(source, 'id_card', 1, { owner = 'John Smith' })
ObsiLib.items.remove(source, 'lockpick', 1)          -- checks the count first, false when short
ObsiLib.items.count(source, 'water')                 -- 3
ObsiLib.items.has(source, 'water', 2)                -- true
ObsiLib.items.canCarry(source, 'gold_bar', 10)
ObsiLib.items.list(source)                           -- { { name, count, metadata, slot } }
ObsiLib.items.counts(source)                         -- { water = 3, bread = 1 }
ObsiLib.items.find(source, 'phone')                  -- { { slot, count, metadata } }
ObsiLib.items.catalog()                              -- { water = { label, weight, image, description } }
ObsiLib.items.label('water')                         -- 'Water'
ObsiLib.items.image('water')                         -- 'nui://ox_inventory/web/images/water.png'
```

Image URLs come from the templates in `ObsiConfig.ItemImages`.

## Usable items

```lua
ObsiLib.items.useable('repairkit', function(source, itemName, metadata, slot)
    if ObsiLib.items.remove(source, itemName, 1, nil, slot) then
        TriggerClientEvent('my_script:repair', source)
    end
end)
```

:::hint{type="info" title="ox_inventory"}
With ox_inventory the item has to call the Obsi Lib export, or be usable with `consume = 0`:

```lua title="ox_inventory/data/items.lua"
['repairkit'] = { label = 'Repair kit', weight = 500, server = { export = 'obsi-lib.useItem' } },
```
:::

## Stashes

```lua
ObsiLib.stash.register('police_evidence', {
    label = 'Evidence', slots = 80, weight = 200000,
    groups = { police = 0 },          -- job = minimum grade
    clientOpen = true,                -- clients may open it with ObsiLib.stash.open
    coords = vec3(441.8, -996.2, 30.7), radius = 2.0,  -- optional distance check for client requests
})

ObsiLib.stash.open(source, 'police_evidence')
ObsiLib.stash.add('police_evidence', 'weapon_pistol', 1, { serial = 'A1B2C3' })
ObsiLib.stash.remove('police_evidence', 'weapon_pistol', 1)
ObsiLib.stash.items('police_evidence')         -- { { name, count, metadata } }
ObsiLib.stash.count('police_evidence', 'weapon_pistol')
```

ox_inventory and qb-inventory use their own stashes.
Other inventories get a stash stored in resource KVP with a small keyboard menu.
Every move is checked on the server (session, counts, carry weight) and rolled back when the second half fails.
