> For the complete documentation index, see [llms.txt](https://fantasy-scripts.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://fantasy-scripts.gitbook.io/docs/weazel-news/exports.md).

# Exports

## Exports and events

How other resources talk to **fs-weazel**.

> #### The brackets are required
>
> ```lua
> exports['fs-weazel']:IsReady()     -- correct
> exports.fs-weazel:IsReady()        -- syntax error
> ```
>
> A hyphen is not valid in Lua's dot syntax, so the second form will not parse. It fails as a red script error at load, not as a helpful "export not found".

***

### Before you call anything

Every export returns a safe empty value (`nil`, `false`) until the resource has finished starting: migrations have to run, the framework bridge has to bind, and the stations have to load. Nothing throws.

```lua
if not exports['fs-weazel']:IsReady() then return end
```

If your resource starts first, either check `IsReady` or wait for fs-weazel to start. Do not assume it is up.

***

### More than one newsroom

A server may run several papers. Where that changes an export, it is noted below — but the short version:

* **Identity exports say which paper somebody works for.** `GetEmployee` and `GetPressCredential` both return the station, because "is this person press" is rarely the whole question when there are two outlets.
* **`SubmitTip` takes a station.** A tip is addressed to one newsroom, and only that newsroom ever sees it.
* Everything else is unchanged.

On a one-station server the station fields are still populated, so code written for one paper keeps working if you later add a second.

***

## Server exports

### IsReady

```lua
exports['fs-weazel']:IsReady()
```

**Returns** `boolean`

True once migrations have run, the framework bridge is bound and the stations are loaded. Every other export returns nothing useful until then.

***

### GetEmployee

```lua
local employee = exports['fs-weazel']:GetEmployee(identifier)
```

| Argument     | Type     |                                                                |
| ------------ | -------- | -------------------------------------------------------------- |
| `identifier` | `string` | Character identifier. ESX: `identifier`. QB/Qbox: `citizenid`. |

**Returns** `table` or `nil`. `nil` means "not news staff at any paper".

```lua
{
    id           = 4,
    name         = 'Dana Kowalski',
    role         = 'senior_journalist',   -- see config/permissions.lua
    status       = 'active',              -- active | suspended | terminated | on_leave
    permissions  = { 'news.view', 'news.create', ... },
    stationId    = 1,
    station      = 'Weazel News',
    stationShort = 'WEAZEL'
}
```

> **`status` is returned but not checked.** A suspended employee still comes back from this. If you want "currently allowed to work", check `status == 'active'` yourself, or use `HasPermission`, which does it for you.

**Example — a press-only door at one paper's building**

```lua
local employee = exports['fs-weazel']:GetEmployee(identifier)
if employee and employee.status == 'active' and employee.stationId == 1 then
    openDoor()
end
```

***

### HasPermission

```lua
local allowed = exports['fs-weazel']:HasPermission(identifier, permission)
```

**Returns** `boolean`

The one to reach for most of the time. It checks three things at once: the person is news staff, their status is `active`, and their role — plus any individual override — grants that permission.

Permission ids are in `config/permissions.lua`. Common ones:

| Permission               | Roughly means                |
| ------------------------ | ---------------------------- |
| `news.view`              | Can open the newsroom at all |
| `news.create`            | Can write                    |
| `news.publish`           | Can put a story out          |
| `news.manage_broadcast`  | Can run the gallery          |
| `news.manage_ads`        | Can approve advertising      |
| `news.view_confidential` | Can see protected sources    |

**Example — a studio door only the broadcast team opens**

```lua
if exports['fs-weazel']:HasPermission(identifier, 'news.manage_broadcast') then
    openStudioDoor()
end
```

To restrict it to one paper's studio, combine with `GetEmployee` and check `stationId`.

***

### HasPressCredential

```lua
local valid = exports['fs-weazel']:HasPressCredential(identifier)
```

**Returns** `boolean`

True only if the person holds a press pass that is **active and not expired**. A different question from `HasPermission`: a pass is a physical credential an officer can ask to see, and it can be revoked without touching somebody's job.

Answers for a pass from **any** newsroom, on purpose — a cordon does not care which paper issued it.

**Example — police cordon check**

```lua
if exports['fs-weazel']:HasPressCredential(identifier) then
    allowThroughCordon()
end
```

***

### GetPressCredential

```lua
local pass = exports['fs-weazel']:GetPressCredential(identifier)
```

**Returns** `table` or `nil`

```lua
{
    serial       = 'WN-0014',
    name         = 'Dana Kowalski',
    status       = 'active',      -- active | expired | revoked
    valid        = true,          -- active AND not past its expiry
    station      = 'Weazel News',
    stationShort = 'WEAZEL'
}
```

Use this when you want to *show* the pass — a serial on a scanner, a name and outlet on a cordon log. Use `HasPressCredential` when you only need yes or no.

> **`status` and `valid` are not the same.** A pass can be `active` and still be `valid = false`, because its expiry has passed and nothing has swept it yet. Always branch on `valid`.

***

### SubmitTip

```lua
local tipId = exports['fs-weazel']:SubmitTip(payload)
```

**Returns** `number` (the tip id) or `nil` if it was rejected.

Pushes a news tip into a newsroom from another resource, so police, EMS, fire or a government script can feed a paper without knowing anything about this one's database.

```lua
exports['fs-weazel']:SubmitTip({
    title       = 'Shots fired on Vinewood Boulevard',
    description = 'Multiple callers. Units en route.',
    location    = 'Vinewood Boulevard',
    coords      = { x = 297.5, y = 180.2, z = 104.4 },
    source      = 'police',
    identifier  = 'char1:abc123',   -- optional, who reported it
    name        = 'Officer Reyes',  -- optional, display name
    stationId   = 1,                -- optional, which paper
})
```

| Field         | Type     |                                                                         |
| ------------- | -------- | ----------------------------------------------------------------------- |
| `title`       | `string` | **Required.** One line.                                                 |
| `description` | `string` | Optional detail.                                                        |
| `location`    | `string` | Optional place name.                                                    |
| `coords`      | `table`  | Optional `{x, y, z}`. Puts a marker on the newsroom map.                |
| `source`      | `string` | `public`, `police`, `ems`, `fire`, `government`, `internal`, `external` |
| `identifier`  | `string` | Optional. Who it came from.                                             |
| `name`        | `string` | Optional display name.                                                  |
| `stationId`   | `number` | Optional. **Omitted, it goes to the first active station.**             |

> **An unrecognised `source` becomes `external`, never `police`.** A resource cannot make its tips look official by sending a typo, and the newsroom records which resource actually called regardless of what the payload claims.

**On `stationId`:** leaving it out was the only sensible default for integrations written before there was more than one paper, and it keeps them working. With two newsrooms, name one — otherwise every automated tip goes to the same paper and the other never hears anything.

To offer a choice, get the list from `WN.Stations.PublicList` server-side, or just hard-code the id you want.

***

## Client exports

### OpenNewspaper

```lua
exports['fs-weazel']:OpenNewspaper()      -- the front page
exports['fs-weazel']:OpenNewspaper(12)    -- straight to article 12
```

Opens the public paper. No employee record needed — anyone can read it. Opens on the combined front page, showing every paper in the city.

**Example — a usable newspaper item**

```lua
RegisterNetEvent('myinventory:usedNewspaper', function()
    exports['fs-weazel']:OpenNewspaper()
end)
```

***

### OpenPortal

```lua
exports['fs-weazel']:OpenPortal('classifieds')
```

| Argument | Values                                         |
| -------- | ---------------------------------------------- |
| `tab`    | `front` · `breaking` · `classifieds` · `onair` |

The same window as `OpenNewspaper`, opened on a chosen tab. Written for phone apps that want their own icons — one for the paper, one for the classifieds — going to the same place.

An unknown tab name falls back to `front` rather than failing.

***

## Events you can listen to

These fire on their own. You do not trigger them; you handle them when you want to react to something a newsroom did.

> **Never trigger these yourself.** They carry no authority — the resource does not act on them — so firing one only misleads other listeners.

### fs-weazel:client:published

Fires on every client when a story goes out, whichever paper published it.

```lua
RegisterNetEvent('fs-weazel:client:published', function(card)
    if card.is_breaking then
        -- your own alert, siren, phone buzz, whatever
    end
end)
```

```lua
{
    id              = 41,
    station_id      = 1,
    headline        = 'Pile-up on Vinewood Boulevard closes three lanes',
    subheadline     = 'Emergency services report no fatalities',
    excerpt         = '...',
    is_breaking     = true,
    published_at    = 1755400000000,
    author_name     = 'Dana Kowalski',
    category_label  = 'Traffic',
    category_colour = '#FCD34D',
    image           = 'https://...',   -- may be nil
    organisation    = 'Weazel News',   -- the publishing paper
    masthead        = 'WEAZEL'
}
```

`organisation` and `masthead` are the **publishing** paper's, not the server default — so a card always names who ran it.

### fs-weazel:client:adRunning

Fires when an advertising campaign starts. Same shape, plus `business`, `contact` and `placement`, with `kind = 'ad'`.

### fs-weazel:client:edition

Fires when a new issue is published — `payload.issue`, `payload.masthead`.

### fs-weazel:client:onAir

Fires when television state changes: a bulletin going live, a cut to a new segment, or a broadcast ending. This is what drives the TV props, and carries the broadcasting station's palette.

***

## What is deliberately not exported

So you do not go looking for it.

**Writing articles.** There is no export to create or publish a story. The approval chain is the point of the resource, and an export that skipped it would let any resource put anything on every screen in the city.

**Reading confidential sources.** Protected behind `news.view_confidential` inside the resource and never exposed. A source's identity leaving this resource would defeat the feature entirely.

**Anything to do with money.** Advertising revenue goes through the framework bridge to each station's own society account. Use your framework's account exports.

**Anything that names a station for somebody else's work.** A caller cannot ask "show me newsroom 2's drafts". The station is derived from the job a character holds, server-side, and that is the rule the whole separation between papers rests on.

If you need something that is not here, the honest answer is usually that it belongs behind a permission check inside this resource rather than as an export out of it.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://fantasy-scripts.gitbook.io/docs/weazel-news/exports.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
