Plugin Configuration

Overview

Plugins can declare default configuration values via the config property on
IPlugin. These defaults are deep-merged into the global config at startup, so
game operators can override any value in config/config.json without touching
plugin code.

Declaring Defaults

Add a config property to your IPlugin object. Nest your values under
plugins.<plugin-name> to avoid collisions with core config keys:

import type { IPlugin } from "../../@types/IPlugin.ts";

const myPlugin: IPlugin = {
  name: "my-plugin",
  version: "1.0.0",

  config: {
    plugins: {
      "my-plugin": {
        maxItems:       50,
        welcomeMessage: "Welcome to my plugin!",
        enabled:        true,
      },
    },
  },

  init: async () => {
    return true;
  },
};

export default myPlugin;

Reading Config

Import getConfig from the Config service:

import { getConfig } from "../../services/Config/mod.ts";

// Read a single value with a fallback
const max     = getConfig<number>("plugins.my-plugin.maxItems")  ?? 50;
const enabled = getConfig<boolean>("plugins.my-plugin.enabled")  ?? true;
const msg     = getConfig<string>("plugins.my-plugin.welcomeMessage") ?? "";

getConfig<T>(key) traverses the merged config using dot-notation and returns
undefined if the key does not exist. Always supply a fallback.

User Overrides

Operators drop their overrides into config/config.json. The plugin’s declared
defaults are the baseline; anything in the file wins:

{
  "server": { "telnet": 4201 },
  "plugins": {
    "my-plugin": {
      "maxItems": 100,
      "welcomeMessage": "Greetings, adventurer!"
    }
  }
}

Sensitive Values

Never store secrets (tokens, API keys, passwords) in config/config.json or
in the plugin’s default config object — that file is typically committed to
source control. Use environment variables instead:

init: async () => {
  const apiKey = Deno.env.get("MY_PLUGIN_API_KEY");
  if (!apiKey) {
    console.error("[my-plugin] MY_PLUGIN_API_KEY is not set — plugin disabled.");
    return false;
  }
  // use apiKey ...
  return true;
},

Full Example

A configurable rate-limiter plugin that reads its window and limit from config:

// src/plugins/ratelimit/index.ts
import type { IPlugin } from "../../@types/IPlugin.ts";
import { getConfig } from "../../services/Config/mod.ts";
import "./commands.ts";

const rateLimitPlugin: IPlugin = {
  name: "ratelimit",
  version: "1.0.0",
  description: "Configurable per-player command rate limiter",

  // Declare defaults — operators can override in config/config.json
  config: {
    plugins: {
      ratelimit: {
        windowMs:  10_000,   // 10-second window
        maxCmds:   20,       // max commands per window
        warnAt:    15,       // warn player at this threshold
      },
    },
  },

  init: async () => {
    const window  = getConfig<number>("plugins.ratelimit.windowMs") ?? 10_000;
    const max     = getConfig<number>("plugins.ratelimit.maxCmds")  ?? 20;
    const warnAt  = getConfig<number>("plugins.ratelimit.warnAt")   ?? 15;

    console.log(`[ratelimit] window=${window}ms max=${max} warnAt=${warnAt}`);
    return true;
  },

  remove: async () => {
    console.log("[ratelimit] removed");
  },
};

export default rateLimitPlugin;