dsh-config-form: A Unified Declarative Rendering Approach for DeepSeek Harness Plugin Settings Pages

Introduction

The DeepSeek Harness ecosystem is plugin-centric. When developing plugins, developers often need to handle settings page form rendering, storage logic, route registration, and security validation themselves. Reinventing the wheel is not only time-consuming but can also introduce security vulnerabilities. dsh-config-form provides a unified settings page container; plugins only need to declare fields to obtain a rendered form and routes.

Plugin Overview

This is a router and renderer, not a framework. It provides a unified settings entry point for all DeepSeek Harness plugins that actively integrate with it. The maintainer is begonia599. Through declarative configuration, plugins can quickly obtain a complete settings form while sharing routing and security check mechanisms.

Core Features

  • Declarative field routing and rendering: Plugins define the form structure through declarations, and this plugin handles routing and rendering.
  • Shared routing and security checks: Provides a unified HTTP route and entry point, centralizing security validation.
  • Secret isolation: Sensitive information (such as tokens) is accessed via ctx.credentials and does not appear in the settings document.
  • Layered parsing and version fencing: Supports layered resolution of configuration values and prevents concurrent write conflicts with version fencing.
  • HTTP API support: Provides HTTP interfaces for listing, details, writing, and secret management.

Installation and Setup

Use the official installation command to complete the installation:

dsh plugin --profile web add dsh-config-form

Typical Usage

Plugin developers need to introduce the configForm dependency and declare the field structure. The standard usage workflow is as follows:

  1. Declare fields: Call ctx.configForm.declare in the plugin code to define configuration items.
  2. Get configuration: Use cfg.get() to retrieve the resolved configuration values.
  3. Watch changes: Use cfg.watch to listen for user save operations and execute follow-up logic.
  4. Handle secrets: Use await cfg.secret('token') to securely obtain sensitive credentials.

Code example:

export const inject = ['configForm']

export function apply(ctx: Context) {
  const cfg = ctx.configForm.declare<Settings>(ctx, {
    id: 'my-plugin',
    title: { zh: '插件标题', en: 'Plugin Title' },
    groups: [
      {
        title: { zh: '常规', en: 'General' },
        fields: [
          { kind: 'text', key: 'settingKey', label: { zh: '设置项', en: 'Setting' }, default: 'value' }
        ]
      }
    ]
  })

  // 读取配置
  cfg.get().settingKey

  // 监听变更
  cfg.watch(next => {
    // 配置已保存
  })

  // 安全获取密钥
  await cfg.secret('token')
}

Applicable Scenarios and Notes

  • Positioning: It is a router and renderer, not a framework.
  • Storage: The plugin author chooses the storage logic. A store object can be passed, or the settings seam can be relied on for automatic saving.
  • Security restrictions: Secrets do not appear in the settings document. Security checks rely on the loopback address, Host header, and Same-Origin Policy. Write operations can only modify declared value fields.
  • Environment requirements: Before installation, confirm that the Node.js version satisfies ^22.19.0 || >=24.0.0.

Conclusion

With this plugin, developers can focus on business logic rather than repetitive UI and security code. For detailed information, refer to the plugin catalog or the source repository.

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye