From e742610e7e6f15275c16c8f0764d784f840e14d5 Mon Sep 17 00:00:00 2001 From: Zhongxuan Wang Date: Tue, 2 Jun 2026 10:56:00 -0700 Subject: [PATCH] docs: register plugin kind before activating it in the plugin guide The "Register Plugin Behavior" guide showed the Activation APIs example (build, validate, initialize) ahead of the Header Plugin Example that registers the `header-plugin` kind. Run on its own, the activation snippet failed with `RuntimeError: ... 'header-plugin' is not registered`, and the "Validate Plugin Configuration" pre-flight did not catch it: an unregistered kind is only a warning under the default `unknown_component="warn"` policy, so the error-only `has_errors` check passed while `initialize()` raised. Reorder register-behavior.mdx so the Header Plugin Example (which registers the kind) precedes the Activation APIs lifecycle, drop the now-redundant "register the plugin kind" list item, and document the validate-warns / initialize-raises behavior in both the register-behavior and validate-configuration guides. The reorder moves whole sections only; no code-block content changed. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Zhongxuan Wang --- docs/build-plugins/register-behavior.mdx | 153 +++++++++--------- docs/build-plugins/validate-configuration.mdx | 8 + 2 files changed, 85 insertions(+), 76 deletions(-) diff --git a/docs/build-plugins/register-behavior.mdx b/docs/build-plugins/register-behavior.mdx index 1e37467a..d995ca77 100644 --- a/docs/build-plugins/register-behavior.mdx +++ b/docs/build-plugins/register-behavior.mdx @@ -25,82 +25,6 @@ That gives the plugin system three important guarantees: Use the context only after validation succeeds. Validation should inspect config and return diagnostics; registration should create runtime objects and attach them to the context. -## Activation APIs - -Use the plugin APIs in this order: - -1. Register the plugin kind. -2. Build a `PluginConfig`. -3. Validate the config. -4. Initialize the config. -5. Inspect the activation report. -6. Clear active config during teardown when needed. - - - -```python -import nemo_relay - -config = nemo_relay.plugin.PluginConfig() -config.components = [ - nemo_relay.plugin.ComponentSpec( - kind="header-plugin", - config={"header_name": "x-tenant", "value": "tenant-a"}, - ) -] - -report = nemo_relay.plugin.validate(config) -active_report = await nemo_relay.plugin.initialize(config) -kinds = nemo_relay.plugin.list_kinds() -nemo_relay.plugin.clear() -``` - - - - -```ts -import * as plugin from 'nemo-relay-node/plugin'; - -const config = plugin.defaultConfig(); -config.components = [ - plugin.ComponentSpec( - 'header-plugin', - { header_name: 'x-tenant', value: 'tenant-a' }, - { enabled: true }, - ), -]; - -const report = plugin.validate(config); -const activeReport = await plugin.initialize(config); -const kinds = plugin.listKinds(); -plugin.clear(); -``` - - - - -```rust -use nemo_relay::plugin::{ - clear_plugin_configuration, initialize_plugins, list_plugin_kinds, validate_plugin_config, - PluginComponentSpec, PluginConfig, -}; - -let mut config = PluginConfig::default(); -let mut component = PluginComponentSpec::new("header-plugin"); -component.config.insert("header_name".into(), "x-tenant".into()); -component.config.insert("value".into(), "tenant-a".into()); -config.components.push(component); - -let report = validate_plugin_config(&config); -let active_report = initialize_plugins(config).await?; -let kinds = list_plugin_kinds(); -clear_plugin_configuration()?; -``` - - - - - ## Header Plugin Example The same model applies in every binding: validate component-local config, then install middleware through the component-scoped registration context. @@ -257,6 +181,83 @@ register_plugin(Arc::new(HeaderPlugin))?; +## Activation APIs + +With the plugin kind registered (see the Header Plugin Example above), use the plugin APIs in this order: + +1. Build a `PluginConfig`. +2. Validate the config. +3. Initialize the config. +4. Inspect the activation report. +5. Clear active config during teardown when needed. + +Register the plugin kind before you initialize. An unregistered kind is reported by `validate()` only as a warning under the default `unknown_component="warn"` policy, so an error-only check still passes, but `initialize()` raises for a kind that was never registered. + + + +```python +import nemo_relay + +config = nemo_relay.plugin.PluginConfig() +config.components = [ + nemo_relay.plugin.ComponentSpec( + kind="header-plugin", + config={"header_name": "x-tenant", "value": "tenant-a"}, + ) +] + +report = nemo_relay.plugin.validate(config) +active_report = await nemo_relay.plugin.initialize(config) +kinds = nemo_relay.plugin.list_kinds() +nemo_relay.plugin.clear() +``` + + + + +```ts +import * as plugin from 'nemo-relay-node/plugin'; + +const config = plugin.defaultConfig(); +config.components = [ + plugin.ComponentSpec( + 'header-plugin', + { header_name: 'x-tenant', value: 'tenant-a' }, + { enabled: true }, + ), +]; + +const report = plugin.validate(config); +const activeReport = await plugin.initialize(config); +const kinds = plugin.listKinds(); +plugin.clear(); +``` + + + + +```rust +use nemo_relay::plugin::{ + clear_plugin_configuration, initialize_plugins, list_plugin_kinds, validate_plugin_config, + PluginComponentSpec, PluginConfig, +}; + +let mut config = PluginConfig::default(); +let mut component = PluginComponentSpec::new("header-plugin"); +component.config.insert("header_name".into(), "x-tenant".into()); +component.config.insert("value".into(), "tenant-a".into()); +config.components.push(component); + +let report = validate_plugin_config(&config); +let active_report = initialize_plugins(config).await?; +let kinds = list_plugin_kinds(); +clear_plugin_configuration()?; +``` + + + + + ## Registration Checklist Before publishing or sharing a plugin: diff --git a/docs/build-plugins/validate-configuration.mdx b/docs/build-plugins/validate-configuration.mdx index e59f8c30..f420768c 100644 --- a/docs/build-plugins/validate-configuration.mdx +++ b/docs/build-plugins/validate-configuration.mdx @@ -126,6 +126,14 @@ Prefer stable diagnostic codes over prose-only messages. The message can improve Use the validation API before initialization and fail deployment if the report contains errors. + +This error check does not catch an unknown or unregistered component kind. Under +the default `unknown_component="warn"` policy that case is reported as a warning, +not an error, so the check below passes while `initialize()` still raises for a +kind that is not registered. Register every kind before initialization, or set +`unknown_component="error"` to make validation fail on unknown kinds. + + ```python