服务器插件
这些插件可用于添加仅靠 UI 扩展无法实现的功能,例如创建新的 API 端点,或使用浏览器环境中不可用的 Node.JS 包。
插件存放在 SillyTavern 的 plugins 目录中,并在服务器启动时加载,但仅当 config.yaml 文件中的 enableServerPlugins 设置为 true 时才会加载。
警告
服务器插件未沙盒化。这意味着它们有可能访问你的整个文件系统,或引入一系列普通 UI 扩展无法造成的安全漏洞。仅安装来自你信任的开发者的服务器插件!
有关所有官方服务器插件的列表,请参见 GitHub 组织列表:https://github.com/search?q=topic%3Aplugin+org%3ASillyTavern&type=Repositories
插件的类型
文件
一个可执行的 JavaScript 文件,扩展名为 ".js"(用于 CommonJS 模块)或 ".mjs"(用于 ES 模块),其中包含一个导出 init 函数的模块。该函数接受一个 Express 路由器(专门为你的插件创建)作为参数,并返回一个 Promise。
该模块还应导出一个 info 对象,其中包含插件的相关信息(id、name 和 description 字符串)。这会向加载器提供插件的信息。
你可以通过该路由器注册路由,这些路由会注册在 /api/plugins/{id}/{route} 路径下。例如,对于 example 插件,router.get('/foo') 会生成这样一个路由:/api/plugins/example/foo。
插件还可以可选地导出一个 exit 函数,用于在关闭服务器时执行清理工作。它不应接受任何参数,且必须返回一个 Promise。
插件导出的 TypeScript 类型约定:
interface PluginInfo {
id: string;
name: string;
description: string;
}
interface Plugin {
init: (router: Router) => Promise<void>;
exit: () => Promise<void>;
info: PluginInfo;
}
"Hello world!" 插件示例请见下方:
/**
* Initialize plugin.
* @param {import('express').Router} router Express router
* @returns {Promise<any>} Promise that resolves when plugin is initialized
*/
async function init(router) {
// Do initialization here...
router.get('/foo', req, res, function () {
res.send('bar');
});
console.log('Example plugin loaded!');
return Promise.resolve();
}
async function exit() {
// Do some clean-up here...
return Promise.resolve();
}
module.exports = {
init,
exit,
info: {
id: 'example',
name: 'Example',
description: 'My cool plugin!',
},
};
目录
你可以通过以下任一方式(按优先级排序)从 plugins 目录的子目录中加载插件:
- 一个
package.json文件,其 "main" 字段包含可执行文件的路径。 - 一个用于 CommonJS 模块的
index.js文件。 - 一个用于 ES 模块的
index.mjs文件。
最终被加载的文件必须导出一个 init 函数和一个 info 对象,其要求与单个文件相同。
目录插件示例(使用 index.js 文件):https://github.com/SillyTavern/SillyTavern-DiscordRichPresence-Server
打包
建议使用打包工具(如 Webpack 或 Browserify)将所有依赖打包到一个文件中。请务必将 "Node" 设置为构建目标。
使用 Webpack 和 TypeScript 的插件模板仓库:https://github.com/SillyTavern/Plugin-WebpackTemplate