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

# Middleware API

> Event middleware system for pre/post processing, logging, and data collection

The Middleware component provides a middleware layer for intercepting events, enabling logging, monitoring, data collection, and side-effects when events fire.

## Overview

Middleware handlers are registered for specific events and execute in priority order when that event is triggered. They are used for:

<CardGroup cols={2}>
  <Card title="Intercept Events" icon="hand">
    Run code when events fire
  </Card>

  <Card title="Log Activity" icon="file-lines">
    Log all event activity automatically
  </Card>

  <Card title="Collect Data" icon="database">
    Gather data from multiple handlers
  </Card>

  <Card title="Side Effects" icon="bolt">
    Trigger additional actions on events
  </Card>
</CardGroup>

<Warning>
  **Important:** Middleware handlers in `TriggerEvent` run **all** registered handlers regardless of return values. Middleware does NOT block or prevent event execution — it runs side-effects alongside events.
</Warning>

***

## Methods

### Add

Register middleware for a specific event.

```lua theme={null}
Middleware:Add(eventName, handler, priority)
```

<ParamField path="eventName" type="string" required>
  Name of the event to intercept
</ParamField>

<ParamField path="handler" type="function" required>
  Middleware function to execute.

  **Parameters:**

  * `source` (number) - Player who triggered event (if applicable)
  * `...` - Additional event parameters
</ParamField>

<ParamField path="priority" type="number" optional default="1">
  Execution priority (lower numbers execute first)
</ParamField>

**Example:**

```lua theme={null}
-- Log all player connections
Middleware:Add("playerConnecting", function(source, name, setKickReason, deferrals)
    Logger:Info("Connections", string.format("Player connecting: %s", name), {
        console = true,
        file = true
    })
end, 50)
```

***

### TriggerEvent

Trigger all middleware handlers for an event. All handlers run in priority order — errors in one handler do not stop others.

```lua theme={null}
Middleware:TriggerEvent(eventName, source, ...)
```

<ParamField path="eventName" type="string" required>
  Event name to trigger
</ParamField>

<ParamField path="source" type="number" required>
  Player source (or 0 if not player-related)
</ParamField>

<ParamField path="..." type="any" optional>
  Additional parameters passed to all handlers
</ParamField>

**Behavior:**

1. Handlers are sorted by priority (lowest first)
2. Each handler runs via `pcall` — errors are caught and printed, never crash the server
3. **All handlers run regardless** — return values are ignored
4. Errors print to console: `[Middleware] ERROR in 'eventName' handler (priority X): error message`

**Example:**

```lua theme={null}
-- Framework internally triggers middleware
Middleware:TriggerEvent("Characters:Spawning", source, characterData)
```

***

### TriggerEventWithData

Trigger middleware and **collect return values** from all handlers into a combined table. This is used when you need handlers to contribute data.

```lua theme={null}
local data = Middleware:TriggerEventWithData(eventName, source, ...)
```

<ParamField path="eventName" type="string" required>
  Event name to trigger
</ParamField>

<ParamField path="source" type="number" required>
  Player source
</ParamField>

<ParamField path="..." type="any" optional>
  Additional parameters
</ParamField>

**Returns:** A combined table of all handler return values. Each handler should return an array of tables. Each returned item gets an `ID` field assigned for ordering.

**Handler return format:**

```lua theme={null}
-- Handler should return an array of tables
Middleware:Add("myEvent", function(source, ...)
    return {
        { name = "Item 1", value = 100 },
        { name = "Item 2", value = 200 }
    }
end)
```

**Example — collecting menu items from multiple resources:**

```lua theme={null}
-- Resource A registers middleware
Middleware:Add("interaction:getOptions", function(source, targetId)
    return {
        { label = "Search", action = "search" },
        { label = "Frisk", action = "frisk" }
    }
end, 10)

-- Resource B registers middleware
Middleware:Add("interaction:getOptions", function(source, targetId)
    return {
        { label = "Give Keys", action = "givekeys" }
    }
end, 20)

-- Triggering code collects all options
local options = Middleware:TriggerEventWithData("interaction:getOptions", source, targetId)
-- options = {
--   { label = "Search", action = "search", ID = 1 },
--   { label = "Frisk", action = "frisk", ID = 2 },
--   { label = "Give Keys", action = "givekeys", ID = 3 }
-- }
```

***

## Priority System

Lower priority numbers execute first:

```lua theme={null}
-- Priority 1 - Executes FIRST (default)
Middleware:Add("event", handler1)

-- Priority 10 - Executes SECOND
Middleware:Add("event", handler2, 10)

-- Priority 100 - Executes THIRD
Middleware:Add("event", handler3, 100)
```

<Note>
  The default priority is `1` if not specified.
</Note>

**Recommended Priorities:**

| Priority | Use Case                    | Example            |
| -------- | --------------------------- | ------------------ |
| 1-10     | Critical handlers, security | Anti-cheat logging |
| 11-50    | Core system handlers        | Permission logging |
| 51-100   | General logging, monitoring | Activity logs      |
| 101+     | Low-priority processing     | Analytics          |

***

## Common Use Cases

### Logging Player Actions

```lua theme={null}
-- Log all admin actions
Middleware:Add("Admin:Action", function(source, action, target, details)
    Logger:Info("Admin", string.format(
        "%s performed %s on %s",
        GetPlayerName(source),
        action,
        tostring(target)
    ), {
        console = true,
        file = true,
        discord = true
    })
end, 50)
```

### Tracking Connections

```lua theme={null}
-- Log player connections with identifiers
Middleware:Add("playerConnecting", function(source, name, setKickReason, deferrals)
    Logger:Info("Connections", string.format("Player connecting: %s (source: %s)", name, source), {
        console = true,
        file = true,
        database = true
    }, {
        name = name,
        source = source,
        timestamp = os.time()
    })
end, 50)
```

### Economy Monitoring

```lua theme={null}
-- Log money transactions
Middleware:Add("Finance:Transaction", function(source, amount, type, target)
    Logger:Info("Economy", string.format(
        "Transaction: $%d (%s) from %s to %s",
        amount, type, tostring(source), tostring(target)
    ), {
        console = true,
        file = true
    })
end, 100)
```

### Anti-Cheat Detection Logging

```lua theme={null}
-- Log suspicious events
Middleware:Add("AntiCheat:Detection", function(source, cheatType, details)
    Logger:Critical("AntiCheat", string.format(
        "Detection: %s by source %s",
        cheatType, tostring(source)
    ), {
        console = true,
        file = true,
        discord = {
            embed = true,
            type = "critical",
            title = "Anti-Cheat Detection",
            content = "@here Cheater detected"
        },
        database = true
    }, {
        source = source,
        cheatType = cheatType,
        details = details,
        timestamp = os.time()
    })
end, 1)
```

### Collecting Data from Multiple Resources

```lua theme={null}
-- Each job resource contributes its duty status
Middleware:Add("Jobs:GetDutyStatus", function(source, ...)
    local policeOnDuty = GetPoliceOnDuty()
    return {
        { job = "police", onDuty = #policeOnDuty, players = policeOnDuty }
    }
end, 10)

Middleware:Add("Jobs:GetDutyStatus", function(source, ...)
    local emsOnDuty = GetEMSOnDuty()
    return {
        { job = "ems", onDuty = #emsOnDuty, players = emsOnDuty }
    }
end, 20)

-- Collect all duty info
local dutyInfo = Middleware:TriggerEventWithData("Jobs:GetDutyStatus", 0)
-- dutyInfo contains entries from all registered handlers
```

***

## Error Handling

Middleware handlers are wrapped in `pcall`. If a handler errors:

1. The error is printed to console with the event name and priority
2. Other handlers **continue to execute** — one error does not stop the chain
3. For `TriggerEventWithData`, errored handlers contribute nothing to the result

```
^1[Middleware] ERROR in 'playerConnecting' handler (priority 50): attempt to index a nil value^7
```

***

## Resource Restart Behavior

Middleware handlers are **cleared when any resource starts** (except the current resource). This means:

* Handlers are re-registered when resources restart
* Stale handlers from stopped resources are cleaned up automatically

***

## Best Practices

<AccordionGroup>
  <Accordion title="Use Appropriate Priorities" icon="sort-numeric-down">
    ```lua theme={null}
    -- ✅ Good: Critical logging first
    Middleware:Add("event", securityLog, 1)
    Middleware:Add("event", generalLog, 50)
    Middleware:Add("event", analytics, 200)
    ```
  </Accordion>

  <Accordion title="Keep Handlers Lightweight" icon="gauge">
    Middleware runs on every event trigger. Keep handlers fast:

    ```lua theme={null}
    -- ✅ Good: Quick logging
    Middleware:Add("event", function(source, data)
        Logger:Info("Monitor", "Event fired", { file = true })
    end, 100)

    -- ❌ Bad: Heavy database query in middleware
    Middleware:Add("event", function(source, data)
        Database.Game:find({ collection = "all_data", query = {} }, function(success, results)
            -- This is too slow for middleware
        end)
    end, 100)
    ```
  </Accordion>

  <Accordion title="Use TriggerEventWithData for Data Collection" icon="database">
    When you need handlers to contribute data, use `TriggerEventWithData`:

    ```lua theme={null}
    -- ✅ Good: Return data arrays for collection
    Middleware:Add("getOptions", function(source, target)
        return {
            { label = "Option A", callback = "doA" },
            { label = "Option B", callback = "doB" }
        }
    end)

    local options = Middleware:TriggerEventWithData("getOptions", source, target)
    ```

    For plain side-effects (logging, notifications), use `TriggerEvent` instead.
  </Accordion>

  <Accordion title="Middleware Cannot Block Events" icon="circle-exclamation">
    Unlike some frameworks, Mythic middleware does NOT support blocking:

    ```lua theme={null}
    -- ❌ This does NOT prevent the event from firing
    Middleware:Add("event", function(source, data)
        return false  -- Return value is IGNORED by TriggerEvent
    end)
    ```

    If you need to prevent an action, implement the check in the event handler itself, not in middleware.
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Event System" icon="bolt" href="/concepts/event-system">
    Understanding the event system
  </Card>

  <Card title="Base API" icon="cube" href="/api/core/base">
    Core framework exports
  </Card>

  <Card title="Logger API" icon="file-lines" href="/api/core/logger">
    Logging component
  </Card>

  <Card title="Callbacks" icon="phone" href="/api/core/callback">
    Request-response communication
  </Card>
</CardGroup>
