服务器插件

这些插件可用于添加仅靠 UI 扩展无法实现的功能,例如创建新的 API 端点,或使用浏览器环境中不可用的 Node.JS 包。

插件存放在 SillyTavern 的 plugins 目录中,并在服务器启动时加载,但仅当 config.yaml 文件中的 enableServerPlugins 设置为 true 时才会加载。

有关所有官方服务器插件的列表,请参见 GitHub 组织列表:https://github.com/search?q=topic%3Aplugin+org%3ASillyTavern&type=Repositories

插件的类型

文件

一个可执行的 JavaScript 文件,扩展名为 ".js"(用于 CommonJS 模块)或 ".mjs"(用于 ES 模块),其中包含一个导出 init 函数的模块。该函数接受一个 Express 路由器(专门为你的插件创建)作为参数,并返回一个 Promise。

该模块还应导出一个 info 对象,其中包含插件的相关信息(idnamedescription 字符串)。这会向加载器提供插件的信息。

你可以通过该路由器注册路由,这些路由会注册在 /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 目录的子目录中加载插件:

  1. 一个 package.json 文件,其 "main" 字段包含可执行文件的路径。
  2. 一个用于 CommonJS 模块的 index.js 文件。
  3. 一个用于 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