mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 07:24:52 +09:00
Plugins had no way to update the config fields and permissions core stores for them, so renaming inventory_sync needed migrations in core packages. A plugin can now declare a migrationEntrypoint. It's loaded on the controller and hosts before configs and roles are read, for every plugin in the plugin list, and attaches handlers to sync hooks for the controller, host and instance configs and roles. lib gets helpers to rename config fields and permissions, and each config gets a hidden <plugin>.version field set after load so migrations can tell which version saved the data. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
2.4 KiB
TypeScript
80 lines
2.4 KiB
TypeScript
/**
|
|
* Helpers for plugin migrations
|
|
* @module lib/migrations
|
|
*/
|
|
import type { Static } from "@sinclair/typebox";
|
|
import type { ConfigSchema } from "./config/classes.js";
|
|
import type Role from "./data/Role.js";
|
|
|
|
type SerializedRole = Static<typeof Role.jsonSchema>;
|
|
|
|
/**
|
|
* Rename a field in a serialized config
|
|
*
|
|
* The value is moved if the old field exists and the new one doesn't. The
|
|
* old field is removed either way.
|
|
*
|
|
* @param config - Serialized config to update.
|
|
* @param from - Current name of the field.
|
|
* @param to - New name of the field.
|
|
* @returns The config passed in.
|
|
*/
|
|
export function renameConfigField(config: ConfigSchema, from: string, to: string) {
|
|
if (Object.hasOwn(config, from)) {
|
|
if (!Object.hasOwn(config, to)) {
|
|
config[to] = config[from];
|
|
}
|
|
delete config[from];
|
|
}
|
|
return config;
|
|
}
|
|
|
|
/**
|
|
* Rename all fields starting with a prefix in a serialized config
|
|
*
|
|
* @example
|
|
* lib.renameConfigPrefix(config, "inventory_sync.", "player_sync.");
|
|
*
|
|
* @param config - Serialized config to update.
|
|
* @param from - Current prefix of the fields.
|
|
* @param to - New prefix of the fields.
|
|
* @returns The config passed in.
|
|
*/
|
|
export function renameConfigPrefix(config: ConfigSchema, from: string, to: string) {
|
|
for (const name of Object.keys(config)) {
|
|
if (name.startsWith(from)) {
|
|
renameConfigField(config, name, to + name.slice(from.length));
|
|
}
|
|
}
|
|
return config;
|
|
}
|
|
|
|
/**
|
|
* Rename a permission in a serialized role
|
|
*
|
|
* @param role - Serialized role to update.
|
|
* @param from - Current name of the permission.
|
|
* @param to - New name of the permission.
|
|
* @returns The role passed in.
|
|
*/
|
|
export function renamePermission(role: SerializedRole, from: string, to: string) {
|
|
return renamePermissionsWith(role, name => (name === from ? to : name));
|
|
}
|
|
|
|
/**
|
|
* Rename all permissions starting with a prefix in a serialized role
|
|
*
|
|
* @param role - Serialized role to update.
|
|
* @param from - Current prefix of the permissions.
|
|
* @param to - New prefix of the permissions.
|
|
* @returns The role passed in.
|
|
*/
|
|
export function renamePermissionPrefix(role: SerializedRole, from: string, to: string) {
|
|
return renamePermissionsWith(role, name => (name.startsWith(from) ? to + name.slice(from.length) : name));
|
|
}
|
|
|
|
function renamePermissionsWith(role: SerializedRole, rename: (name: string) => string) {
|
|
role.permissions = [...new Set(role.permissions.map(rename))];
|
|
return role;
|
|
}
|