Let plugins migrate the data core stores for them

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>
This commit is contained in:
bbassieandClaude Opus 5.5 committed 2026-10-14 15:33:27 +00:00
1 parent 24586a4b7c
commit aec0fc7a1e
19 files changed
+562 -7

No files matched your search

+12 -1
View File
@@ -11,7 +11,7 @@ import { fileURLToPath } from "node:url";
import {
ControllerConfig, Address, RequestError,
InstanceConfig, SystemInfo, Role, ModPack, AccountUpdateEvent,
addPluginConfigFields,
addPluginConfigFields, renamePermissionPrefix,
} from "@clusterio/lib";
import "../setup_logging.js";
@@ -714,6 +714,17 @@ describe("controller/src/Controller", function() {
{ permissions: ["core.instance.save.subscribe"] },
]);
});
it("runs plugin role migrations", function() {
Role.pluginMigrations.attach("test", role => (
renamePermissionPrefix(role, "old_name.", "new_name.")
));
try {
const result = Controller.migrateRoles([{ permissions: ["foo", "old_name.view"] }]);
assert.deepEqual(result, [{ permissions: ["foo", "new_name.view"] }]);
} finally {
Role.pluginMigrations.clear();
}
});
it("does nothing for upto date data", function() {
const role = new Role(
0, "n", "d", new Set("p1", "p2"), 0, false