Plugin config
Declare typed config in package.json under s2script.config. The host materializes defaults ⊕ an admin-editable JSON override at load.
{
"s2script": {
"config": {
"greeting": { "type": "string", "default": "hello", "description": "Chat greeting" },
"max_uses": { "type": "int", "default": 3 },
"cooldown": { "type": "float", "default": 0.75 },
"enabled": { "type": "bool", "default": true }
}
}
} Supported types: string, int, float, bool. Wrong-typed override values degrade to the default and log a warning — never crash.
Reading values
Read through the config object — a plain named import, valid anywhere in your plugin:
import { plugin } from '@s2script/sdk/plugin';
import { config } from '@s2script/sdk/config';
export default plugin((ctx) => {
const greeting = config.getString('greeting');
const maxUses = config.getInt('max_uses');
const cooldown = config.getFloat('cooldown');
const enabled = config.getBool('enabled');
}); Undeclared keys return the type’s zero value (empty string / 0 / false), never throw.
Live reload
Opt in by subscribing on ctx.config — the first onChange starts watching the override file. Edits re-materialize and fire handlers without reloading the plugin:
export default plugin((ctx) => {
ctx.config.onChange(() => {
console.log('config changed → greeting =', config.getString('greeting'));
});
}); No subscriber → config is read once at load (zero watch overhead).
Raw files
config.readFile / config.writeFile read and write plain files under addons/s2script/configs/ (e.g. maplist.txt) — the name includes its extension, and traversal is rejected.
Override files themselves live at addons/s2script/configs/<plugin-id>.json and are auto-generated on first load with defaults and // comments.
See the config module.