Add typed hook system for plugins

Replace invokeHook and the per plugin on* methods with AsyncHook
collections on the controller, host, instance, clusterioctl and web
control objects. Plugin entrypoints export a default function that
receives a load context and attaches handlers to the hooks it needs.
Class exports still load through fromContext with a deprecation
warning. The create templates and docs use the entrypoint function.

This is clusterio/clusterio#921 recreated on top of master after the
ESM migration and the PluginDeclaration permissions change.

Closes #730

Co-Authored-By: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
committed 2026-09-11 22:49:09 +00:00
1 parent 8c03ac15ab
commit 7122cbccf8
64 files changed
+1878 -1184

No files matched your search

@@ -33,11 +33,11 @@ function getInitialValues(config: lib.Config<any>, props: BaseConfigTreeProps) {
return initialValues;
}
function renderInput(inputComponents: Record<string, InputComponent>, def: lib.FieldDefinition, readonly: boolean) {
if (def.inputComponent && Object.prototype.hasOwnProperty.call(inputComponents, def.inputComponent)) {
function renderInput(inputComponents: Map<string, InputComponent>, def: lib.FieldDefinition, readonly: boolean) {
if (def.inputComponent && inputComponents.has(def.inputComponent)) {
// Field.Item will provide the value and onChange props to the component.
type InputPartial = React.ComponentClass<Omit<InputComponentProps, "value" | "onChange">>;
const CustomInput = inputComponents[def.inputComponent] as unknown as InputPartial;
const CustomInput = inputComponents.get(def.inputComponent) as unknown as InputPartial;
return <CustomInput fieldDefinition={def} disabled={readonly} />;
}
if (def.type === "boolean") {
@@ -291,7 +291,7 @@ function computeTreeData(
children: [],
};
if (def.type === "object" && !Object.keys(control.inputComponents).includes(def.inputComponent!)) {
if (def.type === "object" && !control.inputComponents.has(def.inputComponent!)) {
let restartRequiredProps = new Set(def.restartRequiredProps || []);
childNode.title = <Form.Item
label={<>