# Utilities

URL: https://zerodev.ca/docs/kora/developer-documentation/utilities

> The services every module can use through this.kora.



Every module class gets the running Kora instance as `this.kora`. These are the services on it you will use most.

## Console

```js
this.kora.console.log(this.kora.console.levels.info, "Sync finished.");
this.kora.console.log(this.kora.console.levels.error, `Sync failed: ${error.message}`);
```

| Level     | Use it for                                |
| --------- | ----------------------------------------- |
| `info`    | Normal progress.                          |
| `success` | Something finished.                       |
| `warning` | Something went wrong but Kora carries on. |
| `error`   | A failure.                                |
| `debug`   | Extra detail.                             |
| `startup` | Loading and registration messages.        |

An unknown level prints as `info` with a warning. Every line also goes to the dashboard's live console and to `data/logs/<date>.log`, where license keys are shortened.

`this.kora.console.error(error)` prints a large fatal error panel. Kora uses it when it cannot keep running, so prefer `log` with the `error` level in modules.

## Settings

Kora's own settings, such as `LANGUAGE` or `ACCENT_COLOUR`, plus anything you store:

```js
const accent = this.kora.settings.get("ACCENT_COLOUR");
await this.kora.settings.set("example:last_sync", Date.now());
await this.kora.settings.delete("example:last_sync");
```

Settings live in the database and are cached in memory. Prefix your own keys with your module ID. For admin-facing options use a [config class](/docs/kora/developer-documentation/configuration) instead.

## Cache

```js
const prices = this.kora.cache.store("example:prices", { ttl: 60000, max: 200 });

const price = await prices.remember(productId, () => this.fetchPrice(productId));
prices.delete(productId);
```

| Method                     | What it does                                                                                                   |
| -------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `get(key)` / `has(key)`    | Read an entry that has not expired.                                                                            |
| `set(key, value, ttl)`     | Store a value.                                                                                                 |
| `remember(key, load, ttl)` | Return the cached value, or run `load` once and cache the result. Calls made while it loads share one request. |
| `delete(key)` / `clear()`  | Remove one entry or all of them.                                                                               |

`ttl` is in milliseconds and defaults to 10 minutes. `max` defaults to 500 entries, after which the oldest are dropped. `this.kora.cache.clear("example:")` clears every store whose name starts with the prefix.

## Files

`this.kora.data` points at Kora's `data/` folder:

```js
const folder = this.kora.data.ensure("example", "exports");
const file = path.join(folder, "licenses.csv");
this.kora.data.remove("example", "exports");
```

| Method                    | What it does                                     |
| ------------------------- | ------------------------------------------------ |
| `path(...segments)`       | The full path, inside `data/`.                   |
| `module(id, ...segments)` | The same, starting in your module's folder.      |
| `ensure(...segments)`     | Create the folder if needed and return its path. |
| `exists(...segments)`     | Whether it exists.                               |
| `remove(...segments)`     | Delete it and everything in it.                  |

Segments are cleaned so a path can never leave `data/`.

## Audit Log

```js
await this.kora.audit.record({
    type: "example",
    actor: request.actor,
    action: "license.synced",
    target: String(license.id),
    detail: { product: license.product_id }
});
```

| Field     | What it is                                        |
| --------- | ------------------------------------------------- |
| `type`    | Usually your module ID.                           |
| `actor`   | Who did it. Leave it out for the system.          |
| `action`  | What happened.                                    |
| `target`  | What it happened to.                              |
| `detail`  | Any extra JSON.                                   |
| `success` | `false` for a failed attempt. Defaults to `true`. |
| `ip`      | The request's IP address.                         |

Entries show on the **Audit Log** page and fire `audit.recorded`.

## Signing

Kora signs validation responses with an Ed25519 key so SDKs can check they came from your server. You can sign your own data with the same key:

```js
const envelope = this.kora.signer.envelope({ key: license.key, valid: true });
const ok = this.kora.signer.verify(envelope.data, envelope.signature);
```

| Method                       | What it does                                                         |
| ---------------------------- | -------------------------------------------------------------------- |
| `sign(payload)`              | Sign an object. Keys are sorted first, so the order does not matter. |
| `verify(payload, signature)` | Check a signature from `sign`.                                       |
| `envelope(payload)`          | `{ data, signature, algorithm: "ed25519" }`.                         |
| `detached(text)`             | Sign a plain string.                                                 |
| `publicKey()`                | The public key as PEM, for your clients.                             |

## Events

```js
this.kora.events.on("license.created", ({ license }) => {});
await this.kora.emitAsync("example.synced", { count });
```

Use [event classes](/docs/kora/developer-documentation/events) for listeners that belong to your module, so they are removed when it is turned off.

## Packages

List npm packages your module needs in its manifest under `dependencies.node`. Kora installs any that are missing when the module loads, with Bun or npm, without adding them to `package.json`. To install one yourself:

```js
await this.kora.installPackages("csv-stringify");
```
