Config Manager

Plugins can register configuration interfaces that appear as settings pages in the frontend. There are two kinds: a global config manager (one set of values for the whole server) and a per-user config manager (separate values per user).

Global config manager

Registered with ctx.registerConfigManager(manager). One plugin can have at most one global config manager. It appears under Settings → System → Plugin → [your plugin].

ctx.registerConfigManager({
	enable(apiCtx) {
		// apiCtx is available for reading/writing stored values
	},

	async getConfigOptions() {
		const current = await apiCtx.getValue("api-key", "string");
		return {
			type: "section",
			children: [
				{ type: "heading", size: "md", content: "API Settings" },
				{
					type: "text",
					id: "api-key",
					name: "API Key",
					value: current ?? "",
					placeholder: "Enter your API key",
				},
			],
		};
	},

	async update(values) {
		await apiCtx.setValue("api-key", "string", values["api-key"]);
		return this.getConfigOptions();
	},
});

ConfigManagerApiContext

Method Purpose
getValue(key, type, multiple?) Read a stored config value (or array if multiple: true)
setValue(key, type, value) Write a config value (or array)
delete(key) Remove a stored value

Supported value types: "string", "integer", "decimal", "boolean".

Per-user config manager

Registered with ctx.registerUserConfigManager(id, manager). The id is a scoped identifier within your plugin - you can register multiple per-user config managers. Each appears under Settings → User → [your plugin] → [config id].

ctx.registerUserConfigManager("preferences", {
	enable(apiCtx) {},

	canUserAccess(userUuid) {
		return true; // control which users see this settings page
	},

	async getConfigOptions(userUuid) {
		const theme = await apiCtx.getValue(userUuid, "theme", "string");
		return {
			type: "section",
			children: [
				{
					type: "text",
					id: "theme",
					name: "Theme",
					value: theme ?? "dark",
				},
			],
		};
	},

	async update(userUuid, values) {
		await apiCtx.setValue(userUuid, "theme", "string", values["theme"]);
		return this.getConfigOptions(userUuid);
	},
});

UserConfigManagerApiContext

Method Purpose
getValue(userUuid, key, type, multiple?) Read a value for a specific user
setValue(userUuid, key, type, value) Write a value for a specific user
getAllValues(key, type) Read a key's value across all users
delete(userUuid, key) Remove a value for a specific user

Config UI nodes

Both managers return a ConfigNode tree that the frontend renders. Available node types:

Type Fields Renders as
"section" children: ConfigNode[] Container grouping child nodes
"heading" size: "sm" | "md" | "lg", content: string Section heading
"paragraph" content: string Descriptive text
"text" id, name, value, placeholder? Text input field

getConfigOptions returns the initial render. update is called when the user submits the form with the new raw values, and returns the updated render (so you can reflect the saved state back to the UI).