Plugin Configuration Validation in Cordis Using @standard-schema/spec

Cordis validates plugin configuration by treating the static Config property as a Standard Schema and invoking its ~standard.validate method during fiber initialization, throwing a dedicated ValidationError for any constraint violations.

Cordis leverages the @standard-schema/spec package to enforce runtime type safety on plugin configurations. When a plugin defines a schema via its Config static property, the framework automatically validates all provided options against that schema before the plugin's apply function executes.

Declaring Configuration Schemas in Plugins

In Cordis, plugins expose their configuration requirements through a static Config property defined on the Plugin.Base interface.

The Plugin.Base Interface

As defined in packages/core/src/registry.ts, the base plugin interface accepts an optional Config property typed as StandardSchemaV1:

export interface Plugin.Base<T = any> {
  /** optional schema for the plugin's config */
  Config?: StandardSchemaV1<any, T>
}

This property connects the plugin to a concrete schema object that conforms to the Standard Schema specification.

Runtime Schema Storage

When a plugin is registered, Cordis stores its configuration schema on the internal Plugin.Runtime object. From packages/core/src/registry.ts:

runtime = { name, callback, fibers: new DisposableList(), Config: plugin.Config }

This ensures the schema remains accessible throughout the plugin's lifecycle for validation during instantiation.

The Configuration Validation Pipeline

Cordis validates configuration during fiber construction through a dedicated resolution function that interfaces directly with the Standard Schema validator.

Validation Entry Point

The Fiber constructor initiates validation by calling resolveConfig with the runtime object and user-provided configuration. In packages/core/src/fiber.ts:

this.config = resolveConfig(runtime, config)

This single call triggers the entire validation workflow before the plugin receives its configuration.

Schema Resolution and Validation

The resolveConfig function checks for the special ~standard key introduced by @standard-schema/spec and executes the schema's validate method. From packages/core/src/fiber.ts:

const result = runtime.Config['~standard'].validate(config)

The ~standard property contains the standardized validation interface defined by the @standard-schema/spec package, ensuring interoperability with any schema library that implements the specification.

Error Handling with ValidationError

When validation fails, Cordis throws a custom ValidationError that formats schema issues for readability. In packages/core/src/fiber.ts:

if (result.issues) throw new ValidationError(result.issues)

Defined in packages/core/src/fiber.ts (lines 19‑27), this error class bubbles up to the plugin registration point, causing instantiation to fail and logging detailed constraint violations.

Practical Implementation Examples

Defining a Plugin with Schema Validation

Here is a complete example of defining a Cordis plugin with a Standard Schema configuration:

import { StandardSchemaV1 } from '@standard-schema/spec'

export const MyPlugin = {
  name: 'my',
  // Define a schema using the StandardSchemaV1 DSL
  Config: StandardSchemaV1.object({
    port: StandardSchemaV1.number().minimum(0).maximum(65535).default(8080),
    debug: StandardSchemaV1.boolean().default(false),
  }),
  apply(ctx, config) {
    // `config` is already validated and coerced to the correct types
    ctx.logger.info(`Listening on ${config.port}, debug=${config.debug}`)
  },
}

Loading and Validating Plugins

When loading the plugin, valid configurations proceed normally while invalid inputs trigger immediate errors:

import { createContext } from 'cordis'

const ctx = createContext()
await ctx.plugin(MyPlugin, { port: 3000 })   // valid – runs normally
await ctx.plugin(MyPlugin, { port: -1 })    // throws ValidationError

Catching Validation Errors

Handle configuration errors gracefully by catching ValidationError:

try {
  await ctx.plugin(MyPlugin, { port: -1 })
} catch (err) {
  if (err instanceof ValidationError) {
    console.error('Plugin config error:', err.message)
  }
}

Key Source Files and Dependencies

The configuration validation system spans three critical locations in the Cordis core:

  • packages/core/src/registry.ts – Declares Plugin.Base.Config as StandardSchemaV1 and stores the schema on the runtime object during plugin registration.
  • packages/core/src/fiber.ts – Implements resolveConfig, invokes runtime.Config['~standard'].validate, and throws ValidationError when issues are detected.
  • packages/core/src/fiber.ts (lines 19‑27) – Defines the ValidationError class that formats schema validation issues for debugging.
  • packages/core/package.json – Lists @standard-schema/spec as a dependency (^1.1.0), providing the standardized validation interface.

Summary

  • Cordis delegates all configuration validation to @standard-schema/spec, checking plugin configs against Standard Schema definitions before initialization.
  • Plugins declare schemas via the static Config property on Plugin.Base, which gets stored on the Plugin.Runtime object for lifecycle access.
  • The Fiber constructor triggers validation through resolveConfig, which calls the schema's ~standard.validate method.
  • Validation failures throw ValidationError with detailed formatting of schema issues, halting plugin instantiation immediately.
  • No manual validation is required in plugin code; Cordis guarantees type-safe, validated configuration objects in the apply function.

Frequently Asked Questions

What happens if a plugin doesn't define a Config schema?

If the Config property is undefined on the plugin object, Cordis skips schema validation entirely and passes the raw configuration object directly to the plugin's apply function. According to the source in packages/core/src/registry.ts, the Config property is optional on Plugin.Base, making schema validation an opt-in feature for type safety.

Can I use any schema library with Cordis configuration validation?

Yes, any library that implements the Standard Schema specification (@standard-schema/spec) is compatible with Cordis. The framework specifically looks for the ~standard property on the schema object and calls its validate method, as implemented in packages/core/src/fiber.ts, ensuring interoperability across Zod, Valibot, ArkType, or other compliant validators.

How does Cordis handle nested configuration objects?

Cordis delegates nested object validation entirely to the Standard Schema implementation. When resolveConfig calls runtime.Config['~standard'].validate(config) in packages/core/src/fiber.ts, the schema library handles deep validation of nested properties. Any issues found at any depth are aggregated in the result.issues array and thrown as a single ValidationError.

Where is the ValidationError class defined and how do I import it?

The ValidationError class is defined in packages/core/src/fiber.ts between lines 19‑27. You can import it from the @cordis/core package to perform instance checks when catching configuration errors: import { ValidationError } from '@cordis/core'. This allows you to distinguish schema validation failures from other runtime errors during plugin registration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →