> ## Documentation Index
> Fetch the complete documentation index at: https://docs.awokenlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Exports

> The surface every Awoken script is written against, and how to add a backend of your own.

Every export is called on `awoken_bridge`. Nothing here decides whether something may happen, only who carries it out.

```lua theme={"dark"}
local BRIDGE = 'awoken_bridge'
```

## Check the contract first

```lua theme={"dark"}
local version = exports[BRIDGE]:Version()
if version.api < 1 then
    error(('needs bridge api 1, found %d (bridge %s)'):format(version.api, version.resource))
end
```

`api` is the contract and only changes when an existing function changes shape or disappears. `resource` is the build number, which is what belongs in the error: "needs api 2, found 1" is only actionable once you know which bridge is installed.

`Backends()` returns what was actually picked for each job, which is worth printing at boot in any script that genuinely cannot work without, say, an inventory.

## Server

```lua theme={"dark"}
-- Framework
exports[BRIDGE]:Notify(src, msg, type)
exports[BRIDGE]:GetIdentifier(src)
exports[BRIDGE]:GetPlayerName(src)
exports[BRIDGE]:GetJob(src)
exports[BRIDGE]:GetJobInfo(src)          -- name, label, grade, gradeLabel, isBoss, onDuty
exports[BRIDGE]:GetGang(src)
exports[BRIDGE]:CountPolice(jobs)
exports[BRIDGE]:PoliceSources(jobs)

-- Money
exports[BRIDGE]:GetBalance(src, account) -- 'cash' | 'bank' | 'black_money'
exports[BRIDGE]:HasMoney(src, account, amount)
exports[BRIDGE]:AddMoney(src, account, amount)
exports[BRIDGE]:RemoveMoney(src, account, amount, reason)
exports[BRIDGE]:AddDirtyMoney(src, amount, item)

-- Inventory
exports[BRIDGE]:AddItem(src, item, count, metadata)
exports[BRIDGE]:RemoveItem(src, item, count)
exports[BRIDGE]:HasItem(src, item, count)
exports[BRIDGE]:GetItemCount(src, item)

-- Dispatch, evidence, stress, society, xp, logs
exports[BRIDGE]:SendAlert(opts)
exports[BRIDGE]:DropEvidence(src, coords, chance)
exports[BRIDGE]:AddStress(src, amount)
exports[BRIDGE]:SocietyBalance(account)
exports[BRIDGE]:AddXp(src, skill, amount)
exports[BRIDGE]:Log(entry)
```

<Note>
  Accounts are named in your words, `cash`, `bank` and `black_money`, and translated inside each backend. ESX calls cash `money` and keeps the other two as accounts; qb keeps all three in one table. Neither spelling leaks out.
</Note>

## Client

```lua theme={"dark"}
exports[BRIDGE]:GetJob()
exports[BRIDGE]:GetJobInfo()
exports[BRIDGE]:GetGang()
exports[BRIDGE]:GetPlayerName()
exports[BRIDGE]:IsPlayerLoaded()
exports[BRIDGE]:IsDead()
exports[BRIDGE]:Notify(msg, type)

-- Interactions, through whatever target system runs here
exports[BRIDGE]:AddZone(id, opts)
exports[BRIDGE]:AddEntity(id, entity, opts)
exports[BRIDGE]:Remove(id)

exports[BRIDGE]:GiveKeys(plate, vehicle)
exports[BRIDGE]:SetFuel(vehicle, level)
exports[BRIDGE]:DisablePhone(state)
```

## Events

Each backend normalises its framework's own lifecycle events into these, so you listen once rather than carrying three spellings.

| Event                        | Realm  | Fires when                                         |
| ---------------------------- | ------ | -------------------------------------------------- |
| `awoken_bridge:playerLoaded` | both   | a character is in the world                        |
| `awoken_bridge:playerLogout` | both   | they logged out, switched character, or timed out  |
| `awoken_bridge:jobChanged`   | both   | their job or grade changed                         |
| `awoken_bridge:gangChanged`  | client | their gang or grade changed                        |
| `awoken_bridge:dutyChanged`  | server | they went on or off duty                           |
| `awoken_bridge:moneyChanged` | client | cash, bank or dirty money moved                    |
| `awoken_bridge:started`      | client | the bridge itself restarted, so rebuild your zones |

<Note>
  `moneyChanged` carries no amount. The frameworks disagree about what they hand over, and a balance worth showing has to be read back from the server anyway, so it only says to go and look again.
</Note>

## Behaviour worth knowing

<AccordionGroup>
  <Accordion title="Activity is two calls, not one" icon="gauge">
    Ask before letting somebody start, claim once they have. Claiming during the check leaks a slot on every later refusal.

    ```lua theme={"dark"}
    if exports[BRIDGE]:ActivityFull() then return notify('The city is busy enough.') end
    -- they do the work
    local id = exports[BRIDGE]:StartActivity('robbery', src)
    if not id then return notify('Too much going on out there.') end
    -- however it ends
    exports[BRIDGE]:EndActivity(id)
    ```

    The ceiling is off by default, so installing the bridge does not quietly change how much crime your server allows.
  </Accordion>

  <Accordion title="Locks are shared across every Awoken resource" icon="lock">
    Two scripts taking `'heist'` cannot both run, and neither has to know the other exists. That is the point of them living here rather than in a script.
  </Accordion>

  <Accordion title="SkillLevel returns 0 with no skill resource" icon="chart-line">
    Treat a minimum of 0 as "no gate" rather than comparing blindly, or a server without one refuses everybody over experience they have no way to earn.
  </Accordion>

  <Accordion title="Logs fill in the calling resource themselves" icon="file-lines">
    Do not pass `resource`. A script should not have to name itself correctly to get its own channel.
  </Accordion>
</AccordionGroup>

## Adding a backend

Every file under `modules/` ships readable, one per resource the bridge talks to. That is deliberate: they are glue against somebody else's public API, and a server on a fork or a newer build needs to be able to fix one rather than wait for us.

<Steps>
  <Step title="Write the file">
    `modules/dispatch/your_resource.lua`. Copy the nearest existing adapter and change what it sends. Every one starts the same way:

    ```lua theme={"dark"}
    if not IsDuplicityVersion() then return end
    if Config.Dispatch ~= 'your_resource' then return end

    function Dispatch.SendAlert(opts) end
    ```

    The contract each backend has to satisfy is documented at the top of that folder's `main.lua`.
  </Step>

  <Step title="List it in fxmanifest.lua">
    An unlisted backend never loads and `auto` simply never picks it, with nothing in the console to say so.
  </Step>

  <Step title="Name it in config">
    ```lua config/core.lua theme={"dark"}
    Config.Dispatch = 'your_resource'
    ```

    Naming it is what loads it, so auto detection never having heard of it does not matter.
  </Step>
</Steps>

If it is a public resource rather than something in-house, send it to us and we will ship it for everyone.
