# Hooks

URL: https://zerodev.ca/docs/prism/developer-documentation/hooks

> Change how Prism behaves from a module without touching the framework.



The framework never checks for a specific module. When a module needs to change core behavior, it registers a hook on `this.prism.hooks`. Remove the module and its hooks go with it.

```js title="modules/example/main.js"
async onStartup() {
    this.prism.hooks.register("restrict", this.restrict);
}

async onShutdown() {
    this.prism.hooks.unregister("restrict", this.restrict);
}
```

Register in `onStartup()` and unregister in `onShutdown()` with the same function, so turning the module off removes it.

## Registry

| Method                        | What it does                                                                                    |
| ----------------------------- | ----------------------------------------------------------------------------------------------- |
| `register(name, handle)`      | Adds a handle under `name`.                                                                     |
| `unregister(name, handle)`    | Removes it.                                                                                     |
| `has(name)`                   | Whether any handle is registered.                                                               |
| `get(name, ...args)`          | Calls each handle in order and returns the first result that is not `undefined`.                |
| `value(name, ...args)`        | The same as `get`, without waiting. Handles must return plain values.                           |
| `run(name, ...args)`          | Calls every handle and ignores the results.                                                     |
| `restricted(action, context)` | Asks the `restrict` hooks about `action`. Returns the reason as a string, or `""` when allowed. |
| `assert(action, context)`     | Throws the reason when `action` is restricted.                                                  |

## Hooks Prism Calls

| Hook          | Call         | Arguments           | Return                                                                                                                                                   |
| ------------- | ------------ | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `setup`       | `value`      | `()`                | Setup needs, such as `[]` to skip the setup wizard.                                                                                                      |
| `owner`       | `value`      | `()`                | The owner `{ discordId, name }` in place of the stored one.                                                                                              |
| `session`     | `get`        | `(request)`         | A user for visitors with no session. Prism marks it `guest: true`.                                                                                       |
| `permissions` | `get`        | `(user)`            | Fields merged over the signed-in session: `permissions`, `role`, `points`.                                                                               |
| `restrict`    | `restricted` | `(action, context)` | A reason string to block the action, or `undefined` to allow it.                                                                                         |
| `mode`        | `get`        | `({ session })`     | `{ badge, hint, link, server }`. Shows a badge next to the brand. `badge` and `hint` are lang keys, `link` and `server` are `{ label, href }` or `null`. |

## Restrictions

Each action below is passed to `restricted()` before it runs.

| Action                                    | Covers                                                                                  |
| ----------------------------------------- | --------------------------------------------------------------------------------------- |
| `action:<name>`                           | A dashboard action, such as `action:saveSettings`.                                      |
| `write`                                   | Every dashboard write through the API proxy. Context: `{ session, discordId, module }`. |
| `page:<module>:<name>`                    | Hides a module page from the sidebar.                                                   |
| `license`                                 | The online license check at boot.                                                       |
| `login`                                   | The login page.                                                                         |
| `logs`                                    | The **Logs** page and its API.                                                          |
| `owner`                                   | Owner-only settings.                                                                    |
| `modules`, `tokens`, `export`, `settings` | Locks those dashboard sections.                                                         |
| `css`                                     | Custom CSS on the site and the dashboard.                                               |
| `account`                                 | Account and theme pages.                                                                |
| `update`                                  | The auto update timer.                                                                  |
| `restart`                                 | Scheduled auto restarts.                                                                |

The shell receives `restricted`, the subset of `logs`, `owner`, `modules`, `tokens`, `export` and `settings` that is blocked, so the dashboard can hide those controls.

## Demo Module

Every product ships its demo as the `demo` module on the `demo/module` branch. Customer releases leave it out. The demo build adds it and sets `DEMO=true`.

The demo module:

* Sets `hidden: true` in its manifest so it never shows on the **Modules** page.
* Registers its hooks in `onBoot()` only when `process.env.DEMO === "true"`, and unregisters them in `onShutdown()`. Its `setup`, `owner` and `license` hooks let a demo instance start without a license or the setup wizard.
* Lists blocked actions in `actions` and blocked restrictions in `denied`. Anything not listed is allowed.
* Returns its `messages.locked` phrase as the reason, and keeps its badge text in `resources/lang/<code>/common.json`.

```js title="modules/demo/src/handlers/policy.js"
restrict(action) {
    if (this.denied.includes(action)) return this.prism.modules.lang.phrase("demo", "messages", "locked");
    if (action.startsWith("action:") && this.actions.includes(action.slice(7))) return this.prism.modules.lang.phrase("demo", "messages", "locked");
    return undefined;
}
```
