Plugin Development Guide
Ting Reader plugin development starts with declaring capabilities and permissions in plugin.yml, then calling system capabilities through HostGateway from plugin code, with runtime-specific bridge and packaging differences handled last.
How Plugins Call System Capabilities
Plugins should not read the database, build media paths, or bypass user permissions directly. When a plugin needs books, chapters, progress, media URLs, library files, cache, or tasks, it calls HostGateway. HostGateway validates manifest permissions and the current user context.
- Capability registers a plugin capability and determines when the system calls the plugin.
- HostGateway lets a plugin access the host system and determines how it safely reads or operates on system data.
- JavaScript backend methods call
Ting.host.invoke(method, params). web_containerUI sendsmethod: "host.invoke"withpostMessage; the client forwards it to/api/v1/plugin-host/invoke.- WASM calls
ting_env.host_invoke, then reads the JSON result withhost_response_sizeandhost_read_body. - Native libraries receive the Host API through
plugin_set_host_api, then callhost_invoke(method, params_json, result_json).
Manifest: Declare Capabilities and Permissions
capabilities define the entries a plugin exposes, while permissions define which system capabilities it can call. HostGateway rejects calls that do not have matching permissions.
admin_only: true is a plugin-level manifest field and defaults to false. When enabled, the plugin is visible, installable, and callable only by administrators; regular users will not see it in plugin lists, capability discovery, or client UI entries, and cannot invoke its capabilities or protected routes directly.
id: assistant-tools
name: Assistant Tools
version: 1.0.0
min_core_version: 1.4.8
runtime: javascript
entry_point: plugin.js
author: Your Name
description:
zh: 提供客户端入口、工具和后台任务
en: Provides client entries, tools, and background tasks
# Optional: set true for plugins that should be visible and callable only by admins.
admin_only: false
capabilities:
- id: assistant.panel
kind: ui_extension
invoke: openAssistant
slot: global.floating_action
title: { zh: AI 助手, en: AI Assistant }
render:
mode: web_container
entry: ui/index.html
- id: metadata.search
kind: metadata_provider
invoke: searchMetadata
auto_scrape: true
search_fields:
- key: title
label: { zh: 书名, en: Title }
required: true
default_from: book.title
result_fields:
- key: title
label: { zh: 标题, en: Title }
- key: cover_url
label: { zh: 封面, en: Cover }
- id: books.tools
kind: tool_provider
invoke: invokeTool
tools:
- name: books.search
description: Search books the current user can access
permissions:
- type: network_access
value: api.example.com
- type: books_read
- type: progress_read
- type: cache_read
- type: cache_writeCapability and HostGateway Overview
- Capabilities live in
capabilities; they declare what the plugin exposes, who can call it, which runtime function is invoked, and whether client UI is shown. - HostGateway is the only safe way for plugins to access host data, such as books, chapters, progress, media URLs, library files, cache, playlists, and user settings.
- The runtime file does not define the plugin type.
capabilities[].kinddoes. - Every HostGateway call needs the matching
permissionsentry; missing permissions, missing user context, and out-of-scope access are rejected.
For detailed kinds, slots, render modes, HTTP routes, tasks, events, and UI icon rules, see the “Plugin Capability Declarations” page. For HostGateway method parameters, response shapes, Web container bridge details, WASM/Native error codes, and permission tables, see the “HostGateway Reference” page.
Plugin Configuration
When a plugin needs API keys, endpoints, model names, switches, enum options, or numeric parameters, declare config_schema in plugin.yml. For form rendering, sensitive-field encryption, defaults, runtime reads, and common pitfalls, see the “Plugin Configuration: config_schema” page.
Choose a Runtime
JavaScript Runtime
Best for API integrations, metadata processing, tools, plugin-store sources, and lightweight UI backend logic.
WASM Runtime
Best for cross-platform Rust logic, content processing, and compute-heavy tasks.
Native Runtime
Best for format handling, streaming decryption, system libraries, and platform binaries.
Download trpack and Package Plugins
trpack is the Ting Reader plugin development and packaging CLI. It initializes plugin projects, validates plugin.yml, builds .tr packages, generates signing keys, inspects packages, and unpacks packages for debugging.
- Windows x86: trpack-1.0.2-windows-amd64
- Linux x86: trpack-1.0.2-linux-amd64
- Linux ARM: trpack-1.0.2-linux-arm64
- Mac Intel: trpack-1.0.2-darwin-amd64
- Mac M-series: trpack-1.0.2-darwin-arm64
After download, rename the file to trpack or trpack.exe and put it on PATH. On Linux and macOS, run chmod +x trpack first.
| Command | Purpose |
|---|---|
| init | Create a plugin project from templates: metadata, format, ui, route, content, or tool. |
| validate | Validate the plugin directory and plugin.yml/plugin.yaml before packaging. |
| build / pack | Build a .tr package; use --include for extra files and --json for machine-readable output. |
| keygen | Generate an Ed25519 release key so future upgrades keep a stable publisher identity. |
| sign | Add or replace a signature on an existing .tr package. |
| inspect | Inspect package metadata, file table, and signature summary; supports --json. |
| verify | Verify package structure, manifest, file table, and signature status. |
| unpack | Unpack a package into a directory for debugging. |
| is-tr | Quickly check whether a file is a .tr plugin package. |
trpack init my-plugin --template ui --id my-plugin --name "My Plugin"
trpack validate my-plugin
trpack build my-plugin --output dist/my-plugin.tr --json
trpack inspect dist/my-plugin.tr --json
trpack unpack dist/my-plugin.tr --output unpacked
trpack is-tr dist/my-plugin.trPlugins are released as .tr packages. Before publishing, run at least validate, build, and verify to check the manifest, file table, signature metadata, plugin dependencies, and minimum server version.
trpack validate my-plugin
trpack build my-plugin --output dist/my-plugin.tr
trpack verify dist/my-plugin.trFor public releases, use a stable signing key and keep the private key out of source control. Use trpack sign when an existing package needs to be signed again. The current installer only accepts valid .tr packages: unsigned packages are rejected, while valid but untrusted signatures require user confirmation before installation.
trpack keygen --key-id my-plugin-release --output keys/private.json --public-output keys/public.json
trpack build . --output dist/my-plugin.tr --sign-key keys/private.json
trpack sign dist/my-plugin.tr --key keys/private.json --output dist/my-plugin.signed.tr
trpack verify dist/my-plugin.signed.trDo not publish by copying a source directory directly into the server plugin installation directory. Installing a .tr package writes .trpack/package.json and .trpack/signature.json; plugin discovery verifies those files, package file sizes, and sha256 hashes on startup. Editing installed files directly can fail signature verification or cause the plugin to be skipped.
| Runtime | Packaging notes |
|---|---|
| JavaScript | Usually package plugin.yml, the entry script, optional ui/ assets, and local modules. |
| WASM | Compile the .wasm file first, then package it together with plugin.yml. |
| Native | Build .dll/.so/.dylib per platform and use the matching trpack build for each .tr package. |