> For the complete documentation index, see [llms.txt](https://docs.av-scripts.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.av-scripts.com/laptop-pack/laptop/terminal/exports.md).

# Exports

> This page explains how to register and execute commands and actions from external scripts using the terminal's built-in exports.

{% tabs %}
{% tab title="Client" %}

#### addExternal(name,callback)

> Use this export to register a custom callback. It triggers whenever the terminal processes an action with a matching callback value.
>
> **Parameters**
>
> * **name**:`string` Action name, should match the field callback from a server side action.
> * **callback**: `function(data)` Callback to perform
>
> **Return**
>
> * **success**:`boolean` true will allow the command to execute the following actions, false will stop everything and print the failure action.

#### addSuccess(command, callback)

> Use this export to register a onSuccess callback to trigger when a command is completed successfully.
>
> **Parameters**
>
> * **command**:`string` Must be an existing command.
> * **callback**:`function(data)` Callback to perform

#### terminal(action)

> Triggers an array of actions within the terminal, adhering to the format specified in [Terminal](/laptop-pack/laptop/terminal.md)
>
> ```lua
> local actions = {
>     {
>         type = "text",
>         input = "No vehicle found nearby.",
>         style = "error",
>         delay = 0
>     }
> }
> exports['av_laptop']:terminal(actions)
> ```

{% endtab %}

{% tab title="Server" %}

#### addCommand(settings)

> Use this exports server side to register a new command for Terminal.
>
> **Parameters:**
>
> * **command**:`string` Command name, needs to be unique.
> * **show**:`boolean` Makes the command visible for player when using /help command.
> * **allowed**: `function(playerId, laptopSerial)` Should return a boolean, gets triggered when command /help is used and field show is true, is an extra layer where you can run custom code to restrict command access.
> * **canProcess**: `function(playerId, laptopSerial, args)` Should return a boolean, gets triggered when player uses command, use it to verify if the arguments are valid or if the player have X item, etc.
> * **onSuccess**: `function(playerId, laptopSerial, args)` Should return a boolean, triggered when all actions are completed successfully.
> * **actions**:`table` A table with all actions to perform in terminal.
> * **output?**:`table` A final action we can use to display text on terminal if all actions were completed successfully.
>
> **An example running this command can be found below.**
> {% endtab %}
> {% endtabs %}

#### Keyfob Example

This example script registers the `keyfob` command to execute a sequence of actions, demonstrating how to:

* Trigger 3 custom client-side callbacks (`demo:validate`, `demo:getClosest`, and `demo:processKeys`).
* Use the `userInput` action type to pause the sequence and capture the vehicle's SSID.
* Reward the player with the vehicle keys once the entire action sequence is successfully completed.

<figure><img src="/files/owkrjo8XFAlvuS3si5YU" alt=""><figcaption></figcaption></figure>

{% tabs %}
{% tab title="client.lua" %}

```lua
local temp_ids = {}
local temp_vehicle = nil

CreateThread(function()
    while not GetResourceState('av_laptop') == 'started' do
        Wait(100)
    end
    exports['av_laptop']:addExternal("demo:validate", validateInput)
    exports['av_laptop']:addExternal("demo:getClosest", getClosest)
    exports['av_laptop']:addExternal("demo:processKeys", processKeys)
end)

function getClosest()
    local data = {}
    local playerCoords = GetEntityCoords(cache.ped)
    local vehicles = lib.getNearbyVehicles(playerCoords, 10.0)
    for _, v in pairs(vehicles) do
        local veh = type(v) == "table" and (v.vehicle or v.entity) or v
        local plate = GetVehicleNumberPlateText(veh)
        local modelName = exports['av_laptop']:getVehicleName(GetEntityModel(veh))
        local distance = #(playerCoords - GetEntityCoords(veh))
        local cleanModel = string.gsub(modelName, "%s+", "")
        local ssid = string.format("%s_0x%03X", string.upper(string.sub(cleanModel, 1, 6)), math.random(256, 4095))
        temp_ids[ssid] = {
            vehicle = veh,
            plate = plate,
            model = modelName,
            ssid = ssid,
            distance = distance
        }
        table.insert(data, {
            plate,
            modelName,
            ssid,
            string.format("%.1fm", distance)
        })
    end
    if #data == 0 then
        exports['av_laptop']:terminal({
            {
                type = "text",
                input = "No vehicle found nearby.",
                style = "error",
                delay = 0
            }
        })
        return false
    end
    exports['av_laptop']:terminal({
        {
            type = "table",
            columns = {"PLATE", "MODEL", "SSID", "DISTANCE"},
            rows = data,
            delay = 0
        },
    })
    return true
end

function validateInput(args)
    if not args then return false end
    local targetSSID = args['extraData']
    if not targetSSID then
        print("No target ssid provided in args")
        return false
    end
    if temp_ids[targetSSID] then
        temp_vehicle = temp_ids[targetSSID] and temp_ids[targetSSID].vehicle or nil
        if not temp_vehicle then
            print("Vehicle associated with SSID not found, it might have been deleted or gone out of range")
            return false
        end
        local dist = #(GetEntityCoords(cache.ped) - GetEntityCoords(temp_vehicle))
        if dist > 11.0 then
            exports['av_laptop']:terminal({
                {
                    type = "text",
                    input = "Vehicle is too far away.",
                    style = "error",
                    delay = 0
                }
            })
            return false
        end
        return true
    else
        print("Provided SSID does not match any temporary IDs")
        return false
    end
end

function processKeys()
    print("processKeys() called, temp_vehicle:", temp_vehicle)
    if not temp_vehicle then
        print("No vehicle set for processing keys or it got deleted (?)")
        return false
    end
    local plate = GetVehicleNumberPlateText(temp_vehicle)
    TriggerEvent('qb-vehiclekeys:client:AddKeys', plate) -- default qb-vehiclekeys event for giving keys
    return true
end
```

{% endtab %}

{% tab title="server.lua" %}

```lua
local test_command = {
    command = "keyfob", -- command to use in terminal
    show = false, -- Set to true if you want the command to be visible in the terminal command list
    allowed = function(playerId, laptopSerial)
        return true
    end,
    onSuccess = function()
        return true
    end,
    canProcess = function(playerId, laptopSerial, args)
        return true
    end,
    actions = {
        {type = "text", input = "Mounting radio interface...", delay = 800},
        {type = "progressbar", input = "Scanning local frequency spectrum", delay = 3500},
        {type = "text", input = "Filtering encrypted broadcasts...", delay = 800},
        {type = "external", callback = "demo:getClosest"}, -- This action will trigger our client event to get the closest SSID and return it to the next action
        {type = "userInput", input = "Enter target SSID:", color = "yellow", delay = 500, external = "demo:validate"},
        {type = "text", input = "Target isolated. Intercepting data packets...", color = "var(--accent)", delay = 800},
        {type = "progressbar", input = "Synchronizing hardware handshake", delay = 4000},
        {type = "text", input = "Payload captured. Executing decryption protocol...", delay = 500},
        {type = "minigame", input = "sniffer", label = "FOB_CLONING.EXE", delay = 0},
        {type = "external", callback = "demo:processKeys"}
    },
    output = {
        message = "SUCCESS: Keyfob signal cloned.",
        color = "green"
    }
}

CreateThread(function()
    while not GetResourceState('av_laptop') == 'started' do
        Wait(100)
    end
    local added, msg = exports['av_laptop']:addCommand(test_command)
    print("Adding terminal command:", added, msg)
end)
```

{% endtab %}

{% tab title="fxmanifest.lua" %}

```lua
fx_version 'cerulean'
description 'AV Example'
author 'Avilchiis'
version '1.0.0'
lua54 'yes'
games {
'gta5'
}

shared_scripts {
'@ox_lib/init.lua',
}

client_scripts {
'client.lua',
}

server_scripts {
'server.lua'
}

dependencies {
    'ox_lib',
}
```

{% endtab %}
{% endtabs %}
